[
  {
    "path": ".git-blame-ignore-revs",
    "content": "# This is a file used by GitHub to ignore the following commits on `git blame`.\n#\n# You can also do the same thing in your local repository with:\n# $ git config --local blame.ignoreRevsFile .git-blame-ignore-revs\n\n# Expand tabs in C source files\n4d6214f50758ea1738bc45e25776ba852321f513\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: 'github-actions'\n    directory: '/'\n    schedule:\n      interval: 'weekly'\n"
  },
  {
    "path": ".github/workflows/github-pages.yml",
    "content": "name: GitHub Pages\n\non:\n  push:\n    branches:\n      - master\n  workflow_dispatch:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v6\n      - uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: ruby\n          bundler-cache: true # 'bundle install' and cache gems\n      - run: bundle exec rake rdoc\n      - name: Upload GitHub Pages artifact\n        uses: actions/upload-pages-artifact@v5\n        with:\n          path: html\n\n  deploy:\n    needs: build\n    permissions:\n      pages: write\n      id-token: write\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    runs-on: ubuntu-latest\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v5\n"
  },
  {
    "path": ".github/workflows/push_gem.yml",
    "content": "name: Publish gem to rubygems.org\n\non:\n  push:\n    tags:\n      - 'v*'\n\npermissions:\n  contents: read\n\njobs:\n  push:\n    if: github.repository == 'ruby/openssl'\n    runs-on: ubuntu-latest\n\n    environment:\n      name: rubygems.org\n      url: https://rubygems.org/gems/openssl\n\n    permissions:\n      contents: write\n      id-token: write\n\n    strategy:\n      matrix:\n        ruby: [ 'ruby', 'jruby' ]\n\n    steps:\n      - name: Harden Runner\n        uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0\n        with:\n          egress-policy: audit\n\n      - uses: actions/checkout@v6\n\n      - name: Set up Ruby\n        uses: ruby/setup-ruby@v1\n        with:\n          bundler-cache: true\n          ruby-version: ${{ matrix.ruby }}\n\n      - name: Publish to RubyGems\n        uses: rubygems/release-gem@v1\n\n      - name: Create GitHub release\n        run: |\n          tag_name=\"$(git describe --tags --abbrev=0)\"\n          gh release create \"${tag_name}\" --verify-tag --draft --generate-notes pkg/*.gem\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        if: matrix.ruby == 'ruby'\n"
  },
  {
    "path": ".github/workflows/sync-ruby.yml",
    "content": "name: Sync ruby\non:\n  push:\n    branches: [master]\njobs:\n  sync:\n    name: Sync ruby\n    runs-on: ubuntu-latest\n    if: ${{ github.repository_owner == 'ruby' }}\n    steps:\n      - uses: actions/checkout@v6\n\n      - name: Create GitHub App token\n        id: app-token\n        uses: actions/create-github-app-token@v3\n        with:\n          app-id: 2060836\n          private-key: ${{ secrets.RUBY_SYNC_DEFAULT_GEMS_PRIVATE_KEY }}\n          owner: ruby\n          repositories: ruby\n\n      - name: Sync to ruby/ruby\n        uses: convictional/trigger-workflow-and-wait@v1.6.5\n        with:\n          owner: ruby\n          repo: ruby\n          workflow_file_name: sync_default_gems.yml\n          github_token: ${{ steps.app-token.outputs.token }}\n          ref: master\n          client_payload: |\n            {\"gem\":\"${{ github.event.repository.name }}\",\"before\":\"${{ github.event.before }}\",\"after\":\"${{ github.event.after }}\"}\n          propagate_failure: true\n          wait_interval: 10\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: CI\n\non: [push, pull_request, workflow_dispatch]\n\njobs:\n  ruby-versions:\n    uses: ruby/actions/.github/workflows/ruby_versions.yml@master\n    with:\n      engine: cruby-truffleruby\n      min_version: 2.7\n\n  test:\n    needs: ruby-versions\n    name: >-\n      ${{ matrix.os }} ${{ matrix.ruby }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-latest, macos-latest, windows-latest ]\n        ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}\n        exclude:\n          - { os: windows-latest, ruby: truffleruby }\n          - { os: windows-latest, ruby: truffleruby-head }\n        include:\n          - { os: windows-latest, ruby: ucrt }\n          - { os: windows-latest, ruby: mswin }\n\n    steps: &test-steps\n      - name: repo checkout\n        uses: actions/checkout@v6\n\n      - name: load ruby\n        uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: ${{ matrix.ruby }}\n          bundler-cache: true # `bundle install` and cache\n        if: ${{ !endsWith(matrix.os, 'ppc64le') && !endsWith(matrix.os, 's390x') }}\n\n      - name: load ruby from deb package\n        run: |\n          sudo apt update\n          sudo apt install ruby-full bundler\n          sudo bundle install --jobs $(nproc)\n        if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }}\n\n      # See https://github.com/oneclick/rubyinstaller2/issues/60\n      # The builtin DLLs are preferred over the mingw-w64/vcpkg DLLs. This is a\n      # temporary workaround until they update the DLLs to OpenSSL 3.5.x.\n      - name: Update RI2/mswin builtin DLLs\n        run: |\n          $dst = \"$((Get-Item (Get-Command ruby).Definition).DirectoryName)\\ruby_builtin_dlls\"\n          if (\"${{ matrix.ruby }}\" -eq \"mswin\") {\n            $src = \"C:\\vcpkg\\installed\\x64-windows\\bin\"\n          } else {\n            $src = \"$((Get-Item (Get-Command ruby).Definition).DirectoryName)\\..\\msys64\\ucrt64\\bin\"\n          }\n          Copy-Item \"$src\\libcrypto-3-x64.dll\", \"$src\\libssl-3-x64.dll\" $dst\n        if: ${{ matrix.os == 'windows-latest' && (matrix.ruby == '3.2' || matrix.ruby == '3.3' || matrix.ruby == 'mswin') }}\n\n      # Enable the verbose option in mkmf.rb to print the compiling commands.\n      - name: enable mkmf verbose\n        run:  echo \"MAKEFLAGS=V=1\" >> $GITHUB_ENV\n        if: runner.os == 'Linux' || runner.os == 'macOS'\n\n      - name: set flags to check compiler warnings\n        run:  echo \"RUBY_OPENSSL_EXTCFLAGS=-Werror\" >> $GITHUB_ENV\n        if: ${{ !matrix.skip-warnings }}\n\n      - name: rake compile\n        run:  bundle exec rake debug_compiler compile\n\n      - name: rake debug\n        run:  bundle exec rake debug\n\n      - name: rake test\n        run:  bundle exec rake test TESTOPTS=\"-v --no-show-detail-immediately\" OSSL_TEST_ALL=1\n        timeout-minutes: 5\n\n  test-ibm:\n    if: github.repository == 'ruby/openssl'\n    name: ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - os: ubuntu-24.04-ppc64le\n          - os: ubuntu-24.04-s390x\n\n    steps: *test-steps\n\n  test-openssls:\n    name: >-\n      ${{ matrix.openssl }} ${{ matrix.name-extra }}\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        name-extra: [ '' ]\n        openssl:\n          # https://openssl-library.org/source/\n          - openssl-1.1.1w # EOL 2023-09-11, still used by RHEL 8 and Ubuntu 20.04\n          - openssl-3.0.20 # Supported until 2026-09-07 (LTS)\n          - openssl-3.1.8 # EOL 2025-03-14\n          - openssl-3.2.6 # EOL 2025-11-23\n          - openssl-3.3.7 # EOL 2026-04-09\n          - openssl-3.4.5 # Supported until 2026-10-22\n          - openssl-3.5.6 # Supported until 2030-04-08 (LTS)\n          - openssl-3.6.2 # Supported until 2026-11-01\n          - openssl-4.0.0 # Supported until 2027-05-14\n          - openssl-master\n          # http://www.libressl.org/releases.html\n          - libressl-3.9.2 # EOL 2025-04-05\n          - libressl-4.0.1 # EOL 2025-10-08\n          - libressl-4.1.2 # Supported until 2026-04-28\n          - libressl-4.2.1 # Supported until 2026-10-22\n          # https://github.com/aws/aws-lc/tags\n          - aws-lc-latest\n        include:\n          - { name-extra: 'without legacy provider', openssl: openssl-4.0.0, append-configure: 'no-legacy' }\n          - { openssl: aws-lc-latest, skip-warnings: true }\n    steps:\n      - name: repo checkout\n        uses: actions/checkout@v6\n\n      - id: cache-openssl\n        uses: actions/cache@v5\n        with:\n          path: ~/openssl\n          key: openssl-${{ runner.os }}-${{ matrix.openssl }}-${{ matrix.append-configure || 'default' }}\n        if: matrix.openssl != 'openssl-master' && matrix.openssl != 'libressl-master' && matrix.openssl != 'aws-lc-latest'\n\n      - name: Compile OpenSSL library\n        if: steps.cache-openssl.outputs.cache-hit != 'true'\n        run: |\n          # Enable Bash debugging option temporarily for debugging use.\n          set -x\n          mkdir -p tmp/build-openssl && cd tmp/build-openssl\n          case ${{ matrix.openssl }} in\n          openssl-1.*)\n            OPENSSL_COMMIT=$(echo ${{ matrix.openssl }} | sed -e 's/^openssl-/OpenSSL_/' | sed -e 's/\\./_/g')\n            git clone -b $OPENSSL_COMMIT --depth 1 https://github.com/openssl/openssl.git .\n            echo \"Git commit: $(git rev-parse HEAD)\"\n            # shared is required for 1.0.x.\n            ./Configure --prefix=$HOME/openssl --libdir=lib shared linux-x86_64\n            make depend && make -j4 && make install_sw\n            ;;\n          openssl-*)\n            OPENSSL_COMMIT=${{ matrix.openssl == 'openssl-master' && 'master' || matrix.openssl }}\n            git clone -b $OPENSSL_COMMIT --depth 1 https://github.com/openssl/openssl.git .\n            echo \"Git commit: $(git rev-parse HEAD)\"\n            ./Configure --prefix=$HOME/openssl --libdir=lib enable-fips no-tests ${{ matrix.append-configure }}\n            make -j4 && make install_sw && make install_fips\n            ;;\n          libressl-*)\n            curl -L https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/${{ matrix.openssl }}.tar.gz | \\\n              tar xzf - --strip-components=1\n            ./configure --prefix=$HOME/openssl\n            make -j4 && make install\n            ;;\n          aws-lc-*)\n            git clone https://github.com/aws/aws-lc.git .\n            AWS_LC_RELEASE=$(git tag --sort=-creatordate --list \"v*\"  | head -1)\n            git checkout $AWS_LC_RELEASE\n            cmake -DCMAKE_INSTALL_PREFIX=$HOME/openssl -DCMAKE_INSTALL_LIBDIR=lib\n            make -j4 && make install\n            ;;\n          *)\n            false\n            ;;\n          esac\n\n      - name: load ruby\n        uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: '3.0'\n          bundler-cache: true\n\n      - name: enable mkmf verbose\n        run:  echo \"MAKEFLAGS=V=1\" >> $GITHUB_ENV\n\n      - name: set flags to check compiler warnings\n        run:  echo \"RUBY_OPENSSL_EXTCFLAGS=-Werror\" >> $GITHUB_ENV\n        if: ${{ !matrix.skip-warnings }}\n\n      - name: rake compile\n        run:  bundle exec rake debug_compiler compile -- --with-openssl-dir=$HOME/openssl\n\n      - name: rake debug\n        run:  bundle exec rake debug\n\n      - name: rake test\n        run:  bundle exec rake test TESTOPTS=\"-v --no-show-detail-immediately\" OSSL_TEST_ALL=1\n        timeout-minutes: 5\n\n      # Run only the passing tests on the FIPS module as a temporary workaround.\n      # TODO Fix other tests, and run all the tests on FIPS module.\n      - name: rake test_fips\n        run: |\n          sed -e \"s|OPENSSL_DIR|$HOME/openssl|\" tool/openssl_fips.cnf.tmpl > tmp/openssl_fips.cnf\n          export OPENSSL_CONF=$(pwd)/tmp/openssl_fips.cnf\n          bundle exec rake debug\n          bundle exec rake test_fips TESTOPTS=\"-v --no-show-detail-immediately\" OSSL_TEST_ALL=1\n        timeout-minutes: 5\n        if: ${{ startsWith(matrix.openssl, 'openssl-3') || matrix.openssl == 'openssl-master' }}\n"
  },
  {
    "path": ".gitignore",
    "content": "/.bundle\n/Gemfile.lock\n/doc/\n/pkg/\n/tmp/\n/html/\n*.bundle\n*.so\n*.o\next/openssl/mkmf.log\next/openssl/Makefile\next/openssl/extconf.h\n"
  },
  {
    "path": "BSDL",
    "content": "Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer in the\ndocumentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Ruby OpenSSL\n\nThank you for your interest in contributing to Ruby OpenSSL!\n\nThis documentation provides an overview how you can contribute.\n\n## Bugs and feature requests\n\nBugs and feature requests are tracked on [GitHub].\n\nIf you think you found a bug, file a ticket on GitHub. Please DO NOT report\nsecurity issues here, there is a separate procedure which is described on\n[\"Security at ruby-lang.org\"][Ruby Security].\n\nWhen reporting a bug, please make sure you include:\n\n* Ruby version (`ruby -v`)\n* `openssl` gem version (`gem list openssl` and `OpenSSL::VERSION`)\n* OpenSSL library version (`OpenSSL::OPENSSL_VERSION`)\n* A sample file that illustrates the problem or link to the repository or\n  gem that is associated with the bug.\n\nThere are a number of unresolved issues and feature requests for openssl that\nneed review. Before submitting a new ticket, it is recommended to check\n[known issues][Issues].\n\n## Submitting patches\n\nPatches are also very welcome!\n\nPlease submit a [pull request][Compare changes] with your changes.\n\nMake sure that your branch does:\n\n* Have good commit messages\n* Follow Ruby's coding style ([Developer-How-To][Ruby Developer-How-To])\n* Pass the test suite successfully (see \"Testing\")\n\n## Testing\n\nWe have a test suite!\n\nTest cases are located under the [`test/openssl`][GitHub test/openssl]\ndirectory.\n\nYou can run it with the following three commands:\n\n```\n$ bundle install # installs rake-compiler, test-unit, ...\n$ bundle exec rake compile\n$ bundle exec rake test\n```\n\n### With different versions of OpenSSL\n\nRuby OpenSSL supports various versions of the OpenSSL library. The test suite\nneeds to pass on all supported combinations.\n\nIf you want to test, debug, report an issue, or contribute to the Ruby OpenSSL\nor [the OpenSSL project][OpenSSL] in the non-FIPS or the\n[FIPS][OpenSSL README-FIPS] case, compiling OpenSSL from the source by yourself\nis a good practice.\n\nThe following steps are tested in Linux and GCC environment. You can adjust the\ncommands in the steps for a different environment.\n\nTo download the OpenSSL source from the Git repository, you can run the following\ncommands:\n\n```\n$ git clone https://github.com/openssl/openssl.git\n$ cd openssl\n```\n\nYou see the `master` branch used as a development branch. Testing against the\nlatest OpenSSL master branch is a good practice to report an issue to the\nOpenSSL project.\n\n```\n$ git branch | grep '^*'\n* master\n```\n\nIf you test against the latest stable branch, you can run the following command.\nIn this example, the `openssl-3.1` branch is the stable branch of OpenSSL 3.1\nseries.\n\n```\n$ git checkout openssl-3.1\n```\n\nTo configure OpenSSL, you can run the following commands.\n\nIn this example, we use the `OPENSSL_DIR` environment variable to specify the\nOpenSSL installed directory for convenience. Including the commit hash in the\ndirectory name is a good practice.\n\n```\n$ git rev-parse --short HEAD\n0bf18140f4\n\n$ OPENSSL_DIR=$HOME/.openssl/openssl-fips-debug-0bf18140f4\n```\n\nThe following configuration options are useful in this case.\nYou can check [OpenSSL installation document][OpenSSL INSTALL] for details.\n\n* `enable-fips`: Add an option to run with the OpenSSL FIPS module.\n* `enable-trace`: Add an option to enabling tracing log. You can trace logs by\n  implementing a code. See the man page [OSSL_TRACE(3)][OpenSSL OSSL_TRACE] for\n  details.\n* compiler flags\n  * `-Wl,-rpath,$(LIBRPATH)`: Set the runtime shared library path to run the\n    `openssl` command without the `LD_LIBRARY_PATH`. You can check\n    [this document][OpenSSL NOTES-UNIX] for details.\n  * `-O0 -g3 -ggdb3 -gdwarf-5`: You can set debugging compiler flags.\n\n```\n$ ./Configure \\\n  --prefix=$OPENSSL_DIR \\\n  --libdir=lib \\\n  enable-fips \\\n  enable-trace \\\n  '-Wl,-rpath,$(LIBRPATH)' \\\n  -O0 -g3 -ggdb3 -gdwarf-5\n$ make -j4\n$ make install\n```\n\nTo print installed OpenSSL version, you can run the following command:\n\n```\n$ $OPENSSL_DIR/bin/openssl version\nOpenSSL 3.2.0-alpha3-dev  (Library: OpenSSL 3.2.0-alpha3-dev )\n```\n\nChange the current working directory into Ruby OpenSSL's source directory.\n\nTo compile Ruby OpenSSL, you can run the following commands:\n\nSimilarly to when installing `openssl` gem via the `gem` command, you can pass a\n`--with-openssl-dir` argument to `rake compile` to specify the OpenSSL library\n to build against.\n\n* `MAKEFLAGS=\"V=1\"`: Enable the compiler command lines to print in\n  the log.\n* `RUBY_OPENSSL_EXTCFLAGS`: Set extra compiler flags to compile Ruby OpenSSL.\n\n```\n$ bundle exec rake clean\n$ MAKEFLAGS=\"V=1\" \\\n  RUBY_OPENSSL_EXTCFLAGS=\"-O0 -g3 -ggdb3 -gdwarf-5\" \\\n  bundle exec rake compile -- --with-openssl-dir=$OPENSSL_DIR\n```\n\n#### Testing normally in non-FIPS case\n\nTo test Ruby OpenSSL, you can run the following command:\n\n```\n$ bundle exec rake test\n```\n\n#### Testing in FIPS case\n\nTo use OpenSSL 3.0 or later versions in a FIPS-approved manner, you must load the\n`fips` and `base` providers, and also use the property query `fips=yes`. The\nproperty query is used when fetching cryptographic algorithm implementations.\nThis must be done at the startup of a process to avoid implicitly loading the\n`default` provider which has the non-FIPS cryptographic algorithm\nimplementations. See also the man page [fips_module(7)][OpenSSL fips_module].\n\nYou can set this in your OpenSSL configuration file by either appropriately\nmodifying the default OpenSSL configuration file located at\n`OpenSSL::Config::DEFAULT_CONFIG_FILE` or temporarily overriding it with the\n`OPENSSL_CONF` environment variable.\n\nIn this example, we explain on the latter way.\n\nYou can create a OpenSSL FIPS config `openssl_fips.cnf` file based on the\n`openssl_fips.cnf.tmpl` file in this repository, and replacing the placeholder\n`OPENSSL_DIR` with your OpenSSL installed directory.\n\n```\n$ sed -e \"s|OPENSSL_DIR|$OPENSSL_DIR|\" tool/openssl_fips.cnf.tmpl | \\\n  tee $OPENSSL_DIR/ssl/openssl_fips.cnf\n```\n\nYou can see the base and fips providers by running the following command if you\nsetup the OpenSSL FIPS config file properly.\n\n```\n$ OPENSSL_CONF=$OPENSSL_DIR/ssl/openssl_fips.cnf \\\n  $OPENSSL_DIR/bin/openssl list -providers\nProviders:\n  base\n    name: OpenSSL Base Provider\n    version: 3.2.0\n    status: active\n  fips\n    name: OpenSSL FIPS Provider\n    version: 3.2.0\n    status: active\n```\n\nYou can run the current tests in the FIPS module case used in the GitHub\nActions file `test.yml` explained in a later sentence.\n\n```\n$ OPENSSL_CONF=$OPENSSL_DIR/ssl/openssl_fips.cnf \\\n  bundle exec rake test_fips\n```\n\nYou can also run the all the tests in the FIPS module case. You see many\nfailures. We are working in progress to fix the failures. Your contribution is\nwelcome.\n\n```\n$ OPENSSL_CONF=$OPENSSL_DIR/ssl/openssl_fips.cnf \\\n  TEST_RUBY_OPENSSL_FIPS_ENABLED=true \\\n  bundle exec rake test\n```\n\nThe GitHub Actions workflow file [`test.yml`][GitHub test.yml] contains useful\ninformation for building OpenSSL/LibreSSL and testing against them.\n\n## Debugging\n\nYou can use the `OpenSSL.debug = true` to print additional error strings.\n\n## Relation with Ruby source tree\n\nAfter Ruby 2.3, `ext/openssl` was converted into a \"default gem\", a library\nwhich ships with standard Ruby builds but can be upgraded via RubyGems. This\nmeans the development of this gem has migrated to a [separate\nrepository][GitHub] and will be released independently.\n\nThe version included in the Ruby source tree (trunk branch) is synchronized with\nthe latest release.\n\n## Release policy\n\nBug fixes (including security fixes) will be made only for the version series\nincluded in a stable Ruby release.\n\n## Security\n\nIf you discovered a security issue, please send us in private, using the\nsecurity issue handling procedure for Ruby core.\n\nYou can either use [HackerOne] or send an email to security@ruby-lang.org.\n\nPlease see [Security][Ruby Security] page on ruby-lang.org website for details.\n\nReported problems will be published after a fix is released.\n\n_Thanks for your contributions!_\n\n  _\\- The Ruby OpenSSL team_\n\n[GitHub]: https://github.com/ruby/openssl\n[Issues]: https://github.com/ruby/openssl/issues\n[Compare changes]: https://github.com/ruby/openssl/compare\n[GitHub test/openssl]: https://github.com/ruby/openssl/tree/master/test/openssl\n[GitHub test.yml]: https://github.com/ruby/openssl/tree/master/.github/workflows/test.yml\n[Ruby Developer-How-To]: https://github.com/ruby/ruby/wiki/Developer-How-To\n[Ruby Security]: https://www.ruby-lang.org/en/security/\n[HackerOne]: https://hackerone.com/ruby\n[OpenSSL]: https://www.openssl.org/\n[OpenSSL INSTALL]: https://github.com/openssl/openssl/blob/master/INSTALL.md\n[OpenSSL README-FIPS]: https://github.com/openssl/openssl/blob/master/README-FIPS.md\n[OpenSSL NOTES-UNIX]: https://github.com/openssl/openssl/blob/master/NOTES-UNIX.md\n[OpenSSL OSSL_TRACE]: https://www.openssl.org/docs/manmaster/man3/OSSL_TRACE.html\n[OpenSSL fips_module]: https://www.openssl.org/docs/manmaster/man7/fips_module.html\n"
  },
  {
    "path": "COPYING",
    "content": "Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.\nYou can redistribute it and/or modify it under either the terms of the\n2-clause BSDL (see the file BSDL), or the conditions below:\n\n  1. You may make and give away verbatim copies of the source form of the\n     software without restriction, provided that you duplicate all of the\n     original copyright notices and associated disclaimers.\n\n  2. You may modify your copy of the software in any way, provided that\n     you do at least ONE of the following:\n\n       a) place your modifications in the Public Domain or otherwise\n          make them Freely Available, such as by posting said\n\t  modifications to Usenet or an equivalent medium, or by allowing\n\t  the author to include your modifications in the software.\n\n       b) use the modified software only within your corporation or\n          organization.\n\n       c) give non-standard binaries non-standard names, with\n          instructions on where to get the original software distribution.\n\n       d) make other distribution arrangements with the author.\n\n  3. You may distribute the software in object code or binary form,\n     provided that you do at least ONE of the following:\n\n       a) distribute the binaries and library files of the software,\n\t  together with instructions (in the manual page or equivalent)\n\t  on where to get the original distribution.\n\n       b) accompany the distribution with the machine-readable source of\n\t  the software.\n\n       c) give non-standard binaries non-standard names, with\n          instructions on where to get the original software distribution.\n\n       d) make other distribution arrangements with the author.\n\n  4. You may modify and include the part of the software into any other\n     software (possibly commercial).  But some files in the distribution\n     are not written by the author, so that they are not under these terms.\n\n     For the list of those files and their copying conditions, see the\n     file LEGAL.\n\n  5. The scripts and library files supplied as input to or produced as\n     output from the software do not automatically fall under the\n     copyright of the software, but belong to whomever generated them,\n     and may be sold commercially, and may be aggregated with this\n     software.\n\n  6. THIS SOFTWARE IS PROVIDED \"AS IS\" AND WITHOUT ANY EXPRESS OR\n     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\n     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n     PURPOSE.\n"
  },
  {
    "path": "Gemfile",
    "content": "source \"https://rubygems.org\"\n\ngem \"rake\"\ngem \"rake-compiler\"\ngem \"test-unit\", \"~> 3.0\", \">= 3.4.6\"\ngem \"test-unit-ruby-core\"\ngem \"prime\"\ngem \"rdoc\"\n\n# Pulled in by test-unit. power_assert 3.x requires Ruby >= 3.1\ngem \"power_assert\", \"< 3\" if RUBY_VERSION < \"3.1\"\n"
  },
  {
    "path": "History.md",
    "content": "Version 4.0.1\n=============\n\nNotable changes\n---------------\n\n* Add `sync_close` keyword argument to `OpenSSL::SSL::SSLSocket.new` as a\n  short-hand for setting `sync_close` attribute on the created `SSLSocket`\n  instance.\n  [[GitHub #955]](https://github.com/ruby/openssl/issues/955)\n  [[GitHub #996]](https://github.com/ruby/openssl/pull/996)\n\n\nBug fixes\n---------\n\n* Fix uninitialized variables in `OpenSSL::OCSP::BasicResponse#status`.\n  [[GitHub #1004]](https://github.com/ruby/openssl/pull/1004)\n\n\nVersion 4.0.0\n=============\n\nCompatibility\n-------------\n\n* Ruby >= 2.7\n* OpenSSL >= 1.1.1, LibreSSL >= 3.9, and AWS-LC 1.66.0\n  - Removed support for OpenSSL 1.0.2-1.1.0 and LibreSSL 3.1-3.8.\n    [[GitHub #835]](https://github.com/ruby/openssl/issues/835)\n  - Added support for AWS-LC.\n    [[GitHub #833]](https://github.com/ruby/openssl/issues/833)\n\n\nNotable changes\n---------------\n\n* `OpenSSL::SSL`\n  - Reduce overhead when writing to `OpenSSL::SSL::SSLSocket`. `#syswrite` no\n    longer creates a temporary String object.\n    [[GitHub #831]](https://github.com/ruby/openssl/pull/831)\n  - Make `OpenSSL::SSL::SSLContext#min_version=` and `#max_version=` wrap the\n    corresponding OpenSSL APIs directly, and remove the fallback to SSL options.\n    [[GitHub #849]](https://github.com/ruby/openssl/pull/849)\n  - Add `OpenSSL::SSL::SSLContext#sigalgs=` and `#client_sigalgs=` for\n    specifying signature algorithms to use for connections.\n    [[GitHub #895]](https://github.com/ruby/openssl/pull/895)\n  - Rename `OpenSSL::SSL::SSLContext#ecdh_curves=` to `#groups=` following\n    the underlying OpenSSL API rename. This method is no longer specific to\n    ECDHE. The old method remains as an alias.\n    [[GitHub #900]](https://github.com/ruby/openssl/pull/900)\n  - Add `OpenSSL::SSL::SSLSocket#sigalg`, `#peer_sigalg`, and `#group` for\n    getting the signature algorithm and the key agreement group used in the\n    current connection.\n    [[GitHub #908]](https://github.com/ruby/openssl/pull/908)\n  - Enable `SSL_CTX_set_dh_auto()` for servers by default.\n    [[GitHub #924]](https://github.com/ruby/openssl/pull/924)\n  - Improve Ractor compatibility. Note that the internal-use constant\n    `OpenSSL::SSL::SSLContext::DEFAULT_PARAMS` is now frozen.\n    [[GitHub #925]](https://github.com/ruby/openssl/pull/925)\n* `OpenSSL::PKey`\n  - Remove `OpenSSL::PKey::EC::Point#mul` support with array arguments. The\n    underlying OpenSSL API has been removed, and the method has been deprecated\n    since ruby/openssl v3.0.0.\n    [[GitHub #843]](https://github.com/ruby/openssl/pull/843)\n  - `OpenSSL::PKey::{RSA,DSA,DH}#params` uses `nil` to indicate missing fields\n    instead of the number `0`.\n    [[GitHub #774]](https://github.com/ruby/openssl/pull/774)\n  - Unify `OpenSSL::PKey::PKeyError` classes. The former subclasses\n    `OpenSSL::PKey::DHError`, `OpenSSL::PKey::DSAError`,\n    `OpenSSL::PKey::ECError`, and `OpenSSL::PKey::RSAError` have been merged\n    into a single class.\n    [[GitHub #929]](https://github.com/ruby/openssl/pull/929)\n* `OpenSSL::Cipher`\n  - `OpenSSL::Cipher#encrypt` and `#decrypt` no longer accept arguments.\n    Passing passwords has been deprecated since Ruby 1.8.2 (released in 2004).\n    [[GitHub #887]](https://github.com/ruby/openssl/pull/887)\n  - `OpenSSL::Cipher#final` raises `OpenSSL::Cipher::AuthTagError` when the\n    integrity check fails for AEAD ciphers. `OpenSSL::Cipher::AuthTagError` is a\n    new subclass of `OpenSSL::Cipher::CipherError`, which was previously raised.\n    [[GitHub #939]](https://github.com/ruby/openssl/pull/939)\n  - `OpenSSL::Cipher.new` now raises `OpenSSL::Cipher::CipherError` instead of\n    `RuntimeError` when OpenSSL does not recognize the algorithm.\n    [[GitHub #958]](https://github.com/ruby/openssl/pull/958)\n  - Add support for \"fetched\" cipher algorithms with OpenSSL 3.0 or later.\n    [[GitHub #958]](https://github.com/ruby/openssl/pull/958)\n* `OpenSSL::Digest`\n  - `OpenSSL::Digest.new` now raises `OpenSSL::Digest::DigestError` instead of\n    `RuntimeError` when OpenSSL does not recognize the algorithm.\n    [[GitHub #958]](https://github.com/ruby/openssl/pull/958)\n  - Add support for \"fetched\" digest algorithms with OpenSSL 3.0 or later.\n    [[GitHub #958]](https://github.com/ruby/openssl/pull/958)\n* `OpenSSL::ASN1.decode` now assumes a 1950-2049 year range for `UTCTime`\n  according to RFC 5280. It previously used a 1969-2068 range. The encoder\n  has always used the 1950-2049 range.\n  [[GitHub #909]](https://github.com/ruby/openssl/pull/909)\n* `OpenSSL::OpenSSLError`, the base class for all ruby/openssl errors, carry\n  an additional attribute `#errors` to keep the content of OpenSSL's error\n  queue. Also, add `#detailed_message` for Ruby 3.2 or later.\n  [[GitHub #976]](https://github.com/ruby/openssl/pull/976)\n* `OpenSSL::PKCS7.new` raises `OpenSSL::PKCS7::PKCS7Error` instead of\n  `ArgumentError` on error to be consistent with other constructors.\n  [[GitHub #983]](https://github.com/ruby/openssl/pull/983)\n\n\nVersion 3.3.2\n=============\n\nMerged changes in 3.1.3 and 3.2.3.\n\n\nVersion 3.3.1\n=============\n\nMerged changes in 3.1.2 and 3.2.2.\n\n\nVersion 3.3.0\n=============\n\nCompatibility\n-------------\n\n* Ruby version: 2.7 or later\n* OpenSSL version: OpenSSL 1.0.2 or later, and LibreSSL 3.1 or later\n\nNotable changes\n---------------\n\n* `OpenSSL::SSL`\n  - `OpenSSL::SSL::SSLSocket#set_params` no longer sets `#min_version=` to TLS\n    1.0 except when OpenSSL 1.0.2 is used. This has been done to disable\n    SSL 3.0, which is not supported by default in OpenSSL 1.1.0 or later, or in\n    LibreSSL. This lets it respect the system default if the system-wide\n    configuration file specifies a higher minimum protocol version.\n    [[GitHub #710]](https://github.com/ruby/openssl/pull/710)\n  - `OpenSSL::SSL::SSLSocket.new` no longer enables the `OpenSSL::SSL::OP_ALL`\n    SSL options by default and follows the system default.\n    [[GitHub #767]](https://github.com/ruby/openssl/pull/767)\n  - Add the following IO methods to `OpenSSL::SSL::SSLSocket`, which will pass\n    along to the underlying socket: `#local_address`, `#remote_address`,\n    `#close_on_exec=`, `#close_on_exec?`, `#wait`, `#wait_readable`, and\n    `#wait_writable`.\n    [[GitHub #708]](https://github.com/ruby/openssl/pull/708)\n  - Update `OpenSSL::SSL::SSLSocket#gets` to take the `chomp` keyword argument.\n    [[GitHub #708]](https://github.com/ruby/openssl/pull/708)\n  - Make `OpenSSL::SSL::SSLSocket` respect the `IO#timeout` value of the\n    underlying socket on Ruby 3.2 or later. `#timeout` and `#timeout=` methods\n    are also added.\n    [[GitHub #714]](https://github.com/ruby/openssl/pull/714)\n  - Add `OpenSSL::SSL::SSLSocket#close_read` and `#close_write`.\n    [[GitHub #743]](https://github.com/ruby/openssl/pull/743)\n  - Add `OpenSSL::Digest.digests` to get a list of all available digest\n    algorithms.\n    [[GitHub #726]](https://github.com/ruby/openssl/pull/726)\n  - Fix `OpenSSL::SSL::SSLSocket#read_nonblock` clearing the passed String\n    buffer when nothing can be read from the connection.\n    [[GitHub #739]](https://github.com/ruby/openssl/pull/739)\n* Add `#to_text` methods to `OpenSSL::Timestamp::Response`,\n  `OpenSSL::Timestamp::Request`, `OpenSSL::Timestamp::TokenInfo`, and\n  `OpenSSL::PKCS7` to get a human-readable representation of the object.\n  [[GitHub #756]](https://github.com/ruby/openssl/pull/756)\n* Add `OpenSSL::X509::Certificate#tbs_bytes` to get the DER encoding of the\n  TBSCertificate.\n  [[GitHub #753]](https://github.com/ruby/openssl/pull/753)\n* Allow passing `nil` as the digest algorithm to `#sign` methods on\n  `OpenSSL::X509::Certificate`, `OpenSSL::X509::Request`, and\n  `OpenSSL::X509::CRL`. This adds supports for signing with EdDSA keys.\n  [[GitHub #761]](https://github.com/ruby/openssl/pull/761)\n  [[GitHub #804]](https://github.com/ruby/openssl/pull/804)\n* Add `OpenSSL::SSL::SSLSocket#readbyte`.\n  [[GitHub #771]](https://github.com/ruby/openssl/pull/771)\n* Change `OpenSSL::X509::Store#time=` to set the time to the `X509_VERIFY_PARAM`\n  in the `X509_STORE`. This allows `OpenSSL::Timestamp::Response#verify` to\n  verify a signature with the specified timestamp.\n  [[GitHub #770]](https://github.com/ruby/openssl/pull/770)\n* Make `OpenSSL::PKCS7.encrypt`'s third parameter `cipher` mandatory. It had\n  an undocumented default value \"RC2-40-CBC\", which is not only insecure, but\n  also not supported in OpenSSL 3.0 or later.\n  [[GitHub #796]](https://github.com/ruby/openssl/pull/796)\n* Make `OpenSSL::BN` shareable between ractors when frozen.\n  [[GitHub #808]](https://github.com/ruby/openssl/pull/808)\n* Make `OpenSSL::Config` instances frozen by default, and make it shareable\n  between ractors. `OpenSSL::Config::DEFAULT_CONFIG_FILE` is also frozen.\n  [[GitHub #809]](https://github.com/ruby/openssl/pull/809)\n* Add `OpenSSL::PKCS12#set_mac` to configure the MAC parameters and recalculate\n  a MAC for the content.\n  [[GitHub #788]](https://github.com/ruby/openssl/pull/788)\n\nAnd various non-user-visible changes and bug fixes. Please see the commit\nhistory for more details.\n\n\nVersion 3.2.3\n=============\n\nMerged changes in 3.1.3.\n\n\nVersion 3.2.2\n=============\n\nMerged changes in 3.1.2.\n\n\nVersion 3.2.1\n=============\n\nMerged changes in 3.0.3.\n\n\nVersion 3.2.0\n=============\n\nCompatibility\n-------------\n\n* Ruby >= 2.7\n  - Support for Ruby 2.6 has been removed. Note that Ruby 2.6 reached the\n    end-of-life in 2022-04.\n    [[GitHub #639]](https://github.com/ruby/openssl/pull/639)\n* OpenSSL >= 1.0.2 or LibreSSL >= 3.1\n\nNotable changes\n---------------\n\n* Add a stub gemspec for JRuby, which depends on the `jruby-openssl` gem.\n  [[GitHub #598]](https://github.com/ruby/openssl/pull/598)\n* Add support for the FIPS module in OpenSSL 3.0/3.1.\n  [[GitHub #608]](https://github.com/ruby/openssl/pull/608)\n* Rework `OpenSSL::PKey` routines for loading DER or PEM encoded keys for better\n  compatibility with OpenSSL 3.0/3.1 with the FIPS module.\n  [[GitHub #615]](https://github.com/ruby/openssl/pull/615)\n  [[GitHub #669]](https://github.com/ruby/openssl/pull/669)\n* Add `OpenSSL::Provider` module for loading and unloading OpenSSL 3 providers.\n  [[GitHub #635]](https://github.com/ruby/openssl/pull/635)\n* Add `OpenSSL::PKey.new_raw_private_key`, `.new_raw_public_key`,\n  `OpenSSL::PKey::PKey#raw_private_key`, and `#raw_public_key` for public key\n  algorithms that use \"raw private/public key\", such as X25519 and Ed25519.\n  [[GitHub #646]](https://github.com/ruby/openssl/pull/646)\n* Improve OpenSSL error messages to include additional information when\n  it is available in OpenSSL's error queue.\n  [[GitHub #648]](https://github.com/ruby/openssl/pull/648)\n* Change `OpenSSL::SSL::SSLContext#ca_file=` and `#ca_path=` to raise\n  `OpenSSL::SSL::SSLError` instead of printing a warning message.\n  [[GitHub #659]](https://github.com/ruby/openssl/pull/659)\n* Allow `OpenSSL::X509::ExtensionFactory#create_extension` to take OIDs in the\n  dotted-decimal notation.\n  [[GitHub #141]](https://github.com/ruby/openssl/pull/141)\n\n\nVersion 3.1.3\n=============\n\nBug fixes\n---------\n\n* Fix missing NULL check for `EVP_PKEY_get0()` functions with OpenSSL 3.x.\n  [[GitHub #957]](https://github.com/ruby/openssl/pull/957)\n\n\nVersion 3.1.2\n=============\n\nBug fixes\n---------\n\n* Fix crash when attempting to export an incomplete `OpenSSL::PKey::DSA` key.\n  [[GitHub #845]](https://github.com/ruby/openssl/issues/845)\n  [[GitHub #847]](https://github.com/ruby/openssl/pull/847)\n* Remove the `OpenSSL::X509::V_FLAG_CRL_CHECK_ALL` flag from the default store\n  used by `OpenSSL::SSL::SSLContext#set_params`. It causes certificate\n  verification to fail with OpenSSL 3.6.0. It has no effect with any other\n  OpenSSL versions.\n  [[GitHub #949]](https://github.com/ruby/openssl/issues/949)\n  [[GitHub #950]](https://github.com/ruby/openssl/pull/950)\n\n\nVersion 3.1.1\n=============\n\nMerged changes in 3.0.3.\n\n\nVersion 3.1.0\n=============\n\nRuby/OpenSSL 3.1 will be maintained for the lifetime of Ruby 3.2.\n\nMerged bug fixes in 2.2.3 and 3.0.2. Among the new features and changes are:\n\nNotable changes\n---------------\n\n* Add `OpenSSL::SSL::SSLContext#ciphersuites=` to allow setting TLS 1.3 cipher\n  suites.\n  [[GitHub #493]](https://github.com/ruby/openssl/pull/493)\n* Add `OpenSSL::SSL::SSLSocket#export_keying_material` for exporting keying\n  material of the session, as defined in RFC 5705.\n  [[GitHub #530]](https://github.com/ruby/openssl/pull/530)\n* Add `OpenSSL::SSL::SSLContext#keylog_cb=` for setting the TLS key logging\n  callback, which is useful for supporting NSS's SSLKEYLOGFILE debugging output.\n  [[GitHub #536]](https://github.com/ruby/openssl/pull/536)\n* Remove the default digest algorithm from `OpenSSL::OCSP::BasicResponse#sign`\n  and `OpenSSL::OCSP::Request#sign`. Omitting the 5th parameter of these\n  methods used to be equivalent of specifying SHA-1. This default value is now\n  removed and we will let the underlying OpenSSL library decide instead.\n  [[GitHub #507]](https://github.com/ruby/openssl/pull/507)\n* Add `OpenSSL::BN#mod_sqrt`.\n  [[GitHub #553]](https://github.com/ruby/openssl/pull/553)\n* Allow calling `OpenSSL::Cipher#update` with an empty string. This was\n  prohibited to workaround an ancient bug in OpenSSL.\n  [[GitHub #568]](https://github.com/ruby/openssl/pull/568)\n* Fix build on platforms without socket support, such as WASI. `OpenSSL::SSL`\n  will not be defined if OpenSSL is compiled with `OPENSSL_NO_SOCK`.\n  [[GitHub #558]](https://github.com/ruby/openssl/pull/558)\n* Improve support for recent LibreSSL versions. This includes HKDF support in\n  LibreSSL 3.6 and Ed25519 support in LibreSSL 3.7.\n\n\nVersion 3.0.3\n=============\n\nBug fixes\n---------\n\n* Fix a performance regression introduced in v2.1.3 on a buffered write to\n  `SSLSocket`.\n  [[GitHub #706]](https://github.com/ruby/openssl/pull/706)\n* Fix `OpenSSL::PKCS7` to handle PKCS#7 structures without content.\n  [[GitHub #690]](https://github.com/ruby/openssl/pull/690)\n  [[GitHub #752]](https://github.com/ruby/openssl/pull/752)\n* Fix `OpenSSL::ASN1::ObjectId#==` with OIDs without a known name.\n  [[GitHub #791]](https://github.com/ruby/openssl/issues/791)\n  [[GitHub #792]](https://github.com/ruby/openssl/pull/792)\n* Fix `OpenSSL::X509::Certificate#crl_uris` to handle CDP with multiple CRL\n  URIs.\n  [[GitHub #775]](https://github.com/ruby/openssl/issues/775)\n  [[GitHub #776]](https://github.com/ruby/openssl/pull/776)\n* Fix `OpenSSL::Cipher#update` to always make the output buffer `String`\n  independent.\n  [[Bug #20937]](https://bugs.ruby-lang.org/issues/20937)\n  [[GitHub #824]](https://github.com/ruby/openssl/pull/824)\n\n\nVersion 3.0.2\n=============\n\nMerged changes in 2.2.3. Additionally, the following issues are fixed by this\nrelease.\n\nBug fixes\n---------\n\n* Fix OpenSSL::PKey::EC#check_key not working correctly on OpenSSL 3.0.\n  [[GitHub #563]](https://github.com/ruby/openssl/issues/563)\n  [[GitHub #580]](https://github.com/ruby/openssl/pull/580)\n\n\nVersion 3.0.1\n=============\n\nMerged changes in 2.1.4 and 2.2.2. Additionally, the following issues are fixed\nby this release.\n\nBug fixes\n---------\n\n* Add missing type check in OpenSSL::PKey::PKey#sign's optional parameters.\n  [[GitHub #531]](https://github.com/ruby/openssl/pull/531)\n* Work around OpenSSL 3.0's HMAC issues with a zero-length key.\n  [[GitHub #538]](https://github.com/ruby/openssl/pull/538)\n* Fix a regression in OpenSSL::PKey::DSA.generate's default of 'q' size.\n  [[GitHub #483]](https://github.com/ruby/openssl/issues/483)\n  [[GitHub #539]](https://github.com/ruby/openssl/pull/539)\n* Restore OpenSSL::PKey.read's ability to decode \"openssl ecparam -genkey\"\n  output when linked against OpenSSL 3.0.\n  [[GitHub #535]](https://github.com/ruby/openssl/pull/535)\n  [[GitHub #540]](https://github.com/ruby/openssl/pull/540)\n* Restore error checks in OpenSSL::PKey::EC#{to_der,to_pem}.\n  [[GitHub #541]](https://github.com/ruby/openssl/pull/541)\n\n\nVersion 3.0.0\n=============\n\nCompatibility notes\n-------------------\n\n* OpenSSL 1.0.1 and Ruby 2.3-2.5 are no longer supported.\n  [[GitHub #396]](https://github.com/ruby/openssl/pull/396)\n  [[GitHub #466]](https://github.com/ruby/openssl/pull/466)\n\n* OpenSSL 3.0 support is added. It is the first major version bump from OpenSSL\n  1.1 and contains incompatible changes that affect Ruby/OpenSSL.\n  Note that OpenSSL 3.0 support is preliminary and not all features are\n  currently available:\n  [[GitHub #369]](https://github.com/ruby/openssl/issues/369)\n\n  - Deprecate the ability to modify `OpenSSL::PKey::PKey` instances. OpenSSL 3.0\n    made EVP_PKEY structure immutable, and hence the following methods are not\n    available when Ruby/OpenSSL is linked against OpenSSL 3.0.\n    [[GitHub #480]](https://github.com/ruby/openssl/pull/480)\n\n    - `OpenSSL::PKey::RSA#set_key`, `#set_factors`, `#set_crt_params`\n    - `OpenSSL::PKey::DSA#set_pqg`, `#set_key`\n    - `OpenSSL::PKey::DH#set_pqg`, `#set_key`, `#generate_key!`\n    - `OpenSSL::PKey::EC#private_key=`, `#public_key=`, `#group=`, `#generate_key!`\n\n  - Deprecate `OpenSSL::Engine`. The ENGINE API has been deprecated in OpenSSL 3.0\n    in favor of the new \"provider\" concept and will be removed in a future\n    version.\n    [[GitHub #481]](https://github.com/ruby/openssl/pull/481)\n\n* `OpenSSL::SSL::SSLContext#tmp_ecdh_callback` has been removed. It has been\n  deprecated since v2.0.0 because it is incompatible with modern OpenSSL\n  versions.\n  [[GitHub #394]](https://github.com/ruby/openssl/pull/394)\n\n* `OpenSSL::SSL::SSLSocket#read` and `#write` now raise `OpenSSL::SSL::SSLError`\n  if called before a TLS connection is established. Historically, they\n  read/wrote unencrypted data to the underlying socket directly in that case.\n  [[GitHub #9]](https://github.com/ruby/openssl/issues/9)\n  [[GitHub #469]](https://github.com/ruby/openssl/pull/469)\n\n\nNotable changes\n---------------\n\n* Enhance OpenSSL::PKey's common interface.\n  [[GitHub #370]](https://github.com/ruby/openssl/issues/370)\n\n  - Key deserialization: Enhance `OpenSSL::PKey.read` to handle PEM encoding of\n    DH parameters, which used to be only deserialized by `OpenSSL::PKey::DH.new`.\n    [[GitHub #328]](https://github.com/ruby/openssl/issues/328)\n  - Key generation: Add `OpenSSL::PKey.generate_parameters` and\n    `OpenSSL::PKey.generate_key`.\n    [[GitHub #329]](https://github.com/ruby/openssl/issues/329)\n  - Public key signing: Enhance `OpenSSL::PKey::PKey#sign` and `#verify` to use\n    the new EVP_DigestSign() family to enable PureEdDSA support on OpenSSL 1.1.1\n    or later. They also now take optional algorithm-specific parameters for more\n    control.\n    [[GitHub #329]](https://github.com/ruby/openssl/issues/329)\n  - Low-level public key signing and verification: Add\n    `OpenSSL::PKey::PKey#sign_raw`, `#verify_raw`, and `#verify_recover`.\n    [[GitHub #382]](https://github.com/ruby/openssl/issues/382)\n  - Public key encryption: Add `OpenSSL::PKey::PKey#encrypt` and `#decrypt`.\n    [[GitHub #382]](https://github.com/ruby/openssl/issues/382)\n  - Key agreement: Add `OpenSSL::PKey::PKey#derive`.\n    [[GitHub #329]](https://github.com/ruby/openssl/issues/329)\n  - Key comparison: Add `OpenSSL::PKey::PKey#compare?` to conveniently check\n    that two keys have common parameters and a public key.\n    [[GitHub #383]](https://github.com/ruby/openssl/issues/383)\n\n* Add `OpenSSL::BN#set_flags` and `#get_flags`. This can be used in combination\n  with `OpenSSL::BN::CONSTTIME` to force constant-time computation.\n  [[GitHub #417]](https://github.com/ruby/openssl/issues/417)\n\n* Add `OpenSSL::BN#abs` to get the absolute value of the BIGNUM.\n  [[GitHub #430]](https://github.com/ruby/openssl/issues/430)\n\n* Add `OpenSSL::SSL::SSLSocket#getbyte`.\n  [[GitHub #438]](https://github.com/ruby/openssl/issues/438)\n\n* Add `OpenSSL::SSL::SSLContext#tmp_dh=`.\n  [[GitHub #459]](https://github.com/ruby/openssl/pull/459)\n\n* Add `OpenSSL::X509::Certificate.load` to load a PEM-encoded and concatenated\n  list of X.509 certificates at once.\n  [[GitHub #441]](https://github.com/ruby/openssl/pull/441)\n\n* Change `OpenSSL::X509::Certificate.new` to attempt to deserialize the given\n  string first as DER encoding first and then as PEM encoding to ensure the\n  round-trip consistency.\n  [[GitHub #442]](https://github.com/ruby/openssl/pull/442)\n\n* Update various part of the code base to use the modern API. No breaking\n  changes are intended with this. This includes:\n\n  - `OpenSSL::HMAC` uses the EVP API.\n    [[GitHub #371]](https://github.com/ruby/openssl/issues/371)\n  - `OpenSSL::Config` uses native OpenSSL API to parse config files.\n    [[GitHub #342]](https://github.com/ruby/openssl/issues/342)\n\n\nVersion 2.2.3\n=============\n\nBug fixes\n---------\n\n* Fix serveral methods in OpenSSL::PKey::EC::Point attempting to raise an error\n  with an incorrect class, which would end up with a TypeError.\n  [[GitHub #570]](https://github.com/ruby/openssl/pull/570)\n* Fix OpenSSL::PKey::EC::Point#eql? and OpenSSL::PKey::EC::Group#eql?\n  incorrectly treated OpenSSL's internal errors as \"not equal\".\n  [[GitHub #564]](https://github.com/ruby/openssl/pull/564)\n* Fix build with LibreSSL 3.5 or later.\n\n\nVersion 2.2.2\n=============\n\nMerged changes in 2.1.4.\n\n\nVersion 2.2.1\n=============\n\nMerged changes in 2.1.3. Additionally, the following issues are fixed by this\nrelease.\n\nBug fixes\n---------\n\n* Fix crash in `OpenSSL::Timestamp::{Request,Response,TokenInfo}.new` when\n  invalid arguments are given.\n  [[GitHub #407]](https://github.com/ruby/openssl/pull/407)\n* Fix `OpenSSL::Timestamp::Factory#create_timestamp` with LibreSSL on platforms\n  where `time_t` has a different size from `long`.\n  [[GitHub #454]](https://github.com/ruby/openssl/pull/454)\n\n\nVersion 2.2.0\n=============\n\nCompatibility notes\n-------------------\n\n* Remove unsupported MDC2, DSS, DSS1, and SHA algorithms.\n* Remove `OpenSSL::PKCS7::SignerInfo#name` alias for `#issuer`.\n  [[GitHub #266]](https://github.com/ruby/openssl/pull/266)\n* Deprecate `OpenSSL::Config#add_value` and `#[]=` for future removal.\n  [[GitHub #322]](https://github.com/ruby/openssl/pull/322)\n\n\nNotable changes\n---------------\n\n* Change default `OpenSSL::SSL::SSLServer#listen` backlog argument from\n  5 to `Socket::SOMAXCONN`.\n  [[GitHub #286]](https://github.com/ruby/openssl/issues/286)\n* Make `OpenSSL::HMAC#==` use a timing safe string comparison.\n  [[GitHub #284]](https://github.com/ruby/openssl/pull/284)\n* Add support for SHA3 and BLAKE digests.\n  [[GitHub #282]](https://github.com/ruby/openssl/pull/282)\n* Add `OpenSSL::SSL::SSLSocket.open` for opening a `TCPSocket` and\n  returning an `OpenSSL::SSL::SSLSocket` for it.\n  [[GitHub #225]](https://github.com/ruby/openssl/issues/225)\n* Support marshalling of `OpenSSL::X509` and `OpenSSL::PKey` objects.\n  [[GitHub #281]](https://github.com/ruby/openssl/pull/281)\n  [[GitHub #363]](https://github.com/ruby/openssl/pull/363)\n* Add `OpenSSL.secure_compare` for timing safe string comparison for\n  strings of possibly unequal length.\n  [[GitHub #280]](https://github.com/ruby/openssl/pull/280)\n* Add `OpenSSL.fixed_length_secure_compare` for timing safe string\n  comparison for strings of equal length.\n  [[GitHub #269]](https://github.com/ruby/openssl/pull/269)\n* Add `OpenSSL::SSL::SSLSocket#{finished_message,peer_finished_message}`\n  for last finished message sent and received.\n  [[GitHub #250]](https://github.com/ruby/openssl/pull/250)\n* Add `OpenSSL::Timestamp` module for handing timestamp requests and\n  responses.\n  [[GitHub #204]](https://github.com/ruby/openssl/pull/204)\n* Add helper methods for `OpenSSL::X509::Certificate`:\n  `find_extension`, `subject_key_identifier`,\n  `authority_key_identifier`, `crl_uris`, `ca_issuer_uris` and\n  `ocsp_uris`, and for `OpenSSL::X509::CRL`:\n  `find_extension` and `subject_key_identifier`.\n  [[GitHub #260]](https://github.com/ruby/openssl/pull/260)\n  [[GitHub #275]](https://github.com/ruby/openssl/pull/275)\n  [[GitHub #293]](https://github.com/ruby/openssl/pull/293)\n* Add `OpenSSL::ECPoint#add` for performing elliptic curve point addition.\n  [[GitHub #261]](https://github.com/ruby/openssl/pull/261)\n* Make `OpenSSL::PKey::RSA#{export,to_der}` check `key`, `factors`, and\n  `crt_params` to do proper private key serialization.\n  [[GitHub #258]](https://github.com/ruby/openssl/pull/258)\n* Add `OpenSSL::SSL::{SSLSocket,SSLServer}#fileno`, returning the\n  underlying socket file descriptor number.\n  [[GitHub #247]](https://github.com/ruby/openssl/pull/247)\n* Support client certificates with TLS 1.3, and support post-handshake\n  authentication with OpenSSL 1.1.1+.\n  [[GitHub #239]](https://github.com/ruby/openssl/pull/239)\n* Add `OpenSSL::ASN1::ObjectId#==` for equality testing.\n* Add `OpenSSL::X509::Extension#value_der` for the raw value of\n  the extension.\n  [[GitHub #234]](https://github.com/ruby/openssl/pull/234)\n* Significantly reduce allocated memory in `OpenSSL::Buffering#do_write`.\n  [[GitHub #212]](https://github.com/ruby/openssl/pull/212)\n* Ensure all valid IPv6 addresses are considered valid as elements\n  of subjectAlternativeName in certificates.\n  [[GitHub #185]](https://github.com/ruby/openssl/pull/185)\n* Allow recipient's certificate to be omitted in PCKS7#decrypt.\n  [[GitHub #183]](https://github.com/ruby/openssl/pull/183)\n* Add support for reading keys in PKCS #8 format and export via instance methods\n  added to `OpenSSL::PKey` classes: `private_to_der`, `private_to_pem`,\n  `public_to_der` and `public_to_pem`.\n  [[GitHub #297]](https://github.com/ruby/openssl/pull/297)\n\n\nVersion 2.1.4\n=============\n\nBug fixes\n---------\n\n* Do not use pkg-config if --with-openssl-dir option is specified.\n [[GitHub #486]](https://github.com/ruby/openssl/pull/486)\n\n\nVersion 2.1.3\n=============\n\nBug fixes\n---------\n\n* Fix deprecation warnings on Ruby 3.0.\n* Add \".include\" directive support in `OpenSSL::Config`.\n  [[GitHub #216]](https://github.com/ruby/openssl/pull/216)\n* Fix handling of IPv6 address SANs.\n  [[GitHub #185]](https://github.com/ruby/openssl/pull/185)\n* Hostname verification failure with `OpenSSL::SSL::SSLContext#verify_hostname=`\n  sets a proper error code.\n  [[GitHub #350]](https://github.com/ruby/openssl/pull/350)\n* Fix crash with `OpenSSL::BN.new(nil, 2)`.\n  [[Bug #15760]](https://bugs.ruby-lang.org/issues/15760)\n* `OpenSSL::SSL::SSLSocket#sys{read,write}` prevent internal string buffers from\n  being modified by another thread.\n  [[GitHub #453]](https://github.com/ruby/openssl/pull/453)\n* Fix misuse of input record separator in `OpenSSL::Buffering` where it was\n  for output.\n* Fix wrong integer casting in `OpenSSL::PKey::EC#dsa_verify_asn1`.\n  [[GitHub #460]](https://github.com/ruby/openssl/pull/460)\n* `extconf.rb` explicitly checks that OpenSSL's version number is 1.0.1 or\n  newer but also less than 3.0. Ruby/OpenSSL v2.1.x and v2.2.x will not support\n  OpenSSL 3.0 API.\n  [[GitHub #458]](https://github.com/ruby/openssl/pull/458)\n* Activate `digest` gem correctly. `digest` library could go into an\n  inconsistent state if there are multiple versions of `digest` is installed\n  and `openssl` is `require`d before `digest`.\n  [[GitHub #463]](https://github.com/ruby/openssl/pull/463)\n* Fix GC.compact compatibility.\n  [[GitHub #464]](https://github.com/ruby/openssl/issues/464)\n  [[GitHub #465]](https://github.com/ruby/openssl/pull/465)\n\n\nVersion 2.1.2\n=============\n\nMerged changes in 2.0.9.\n\n\nVersion 2.1.1\n=============\n\nMerged changes in 2.0.8.\n\n\nVersion 2.1.0\n=============\n\nNotable changes\n---------------\n\n* Support for OpenSSL versions before 1.0.1 and LibreSSL versions before 2.5\n  is removed.\n  [[GitHub #86]](https://github.com/ruby/openssl/pull/86)\n* OpenSSL::BN#negative?, #+@, and #-@ are added.\n* OpenSSL::SSL::SSLSocket#connect raises a more informative exception when\n  certificate verification fails.\n  [[GitHub #99]](https://github.com/ruby/openssl/pull/99)\n* OpenSSL::KDF module is newly added. In addition to PBKDF2-HMAC that has moved\n  from OpenSSL::PKCS5, scrypt and HKDF are supported.\n  [[GitHub #109]](https://github.com/ruby/openssl/pull/109)\n  [[GitHub #173]](https://github.com/ruby/openssl/pull/173)\n* OpenSSL.fips_mode is added. We had the setter, but not the getter.\n  [[GitHub #125]](https://github.com/ruby/openssl/pull/125)\n* OpenSSL::OCSP::Request#signed? is added.\n* OpenSSL::ASN1 handles the indefinite length form better. OpenSSL::ASN1.decode\n  no longer wrongly treats the end-of-contents octets as part of the content.\n  OpenSSL::ASN1::ASN1Data#infinite_length is renamed to #indefinite_length.\n  [[GitHub #98]](https://github.com/ruby/openssl/pull/98)\n* OpenSSL::X509::Name#add_entry now accepts two additional keyword arguments\n  'loc' and 'set'.\n  [[GitHub #94]](https://github.com/ruby/openssl/issues/94)\n* OpenSSL::SSL::SSLContext#min_version= and #max_version= are added to replace\n  #ssl_version= that was built on top of the deprecated OpenSSL C API. Use of\n  that method and the constant OpenSSL::SSL::SSLContext::METHODS is now\n  deprecated.\n  [[GitHub #142]](https://github.com/ruby/openssl/pull/142)\n* OpenSSL::X509::Name#to_utf8 is added.\n  [[GitHub #26]](https://github.com/ruby/openssl/issues/26)\n  [[GitHub #143]](https://github.com/ruby/openssl/pull/143)\n* OpenSSL::X509::{Extension,Attribute,Certificate,CRL,Revoked,Request} can be\n  compared with == operator.\n  [[GitHub #161]](https://github.com/ruby/openssl/pull/161)\n* TLS Fallback Signaling Cipher Suite Value (SCSV) support is added.\n  [[GitHub #165]](https://github.com/ruby/openssl/pull/165)\n* Build failure with OpenSSL 1.1 built with no-deprecated is fixed.\n  [[GitHub #160]](https://github.com/ruby/openssl/pull/160)\n* OpenSSL::Buffering#write accepts an arbitrary number of arguments.\n  [[Feature #9323]](https://bugs.ruby-lang.org/issues/9323)\n  [[GitHub #162]](https://github.com/ruby/openssl/pull/162)\n* OpenSSL::PKey::RSA#sign_pss and #verify_pss are added. They perform RSA-PSS\n  signature and verification.\n  [[GitHub #75]](https://github.com/ruby/openssl/issues/75)\n  [[GitHub #76]](https://github.com/ruby/openssl/pull/76)\n  [[GitHub #169]](https://github.com/ruby/openssl/pull/169)\n* OpenSSL::SSL::SSLContext#add_certificate is added.\n  [[GitHub #167]](https://github.com/ruby/openssl/pull/167)\n* OpenSSL::PKey::EC::Point#to_octet_string is added.\n  OpenSSL::PKey::EC::Point.new can now take String as the second argument.\n  [[GitHub #177]](https://github.com/ruby/openssl/pull/177)\n\n\nVersion 2.0.9\n=============\n\nSecurity fixes\n--------------\n\n* OpenSSL::X509::Name#<=> could incorrectly return 0 (= equal) for non-equal\n  objects. CVE-2018-16395 is assigned for this issue.\n  https://hackerone.com/reports/387250\n\nBug fixes\n---------\n\n* Fixed OpenSSL::PKey::\\*.{new,generate} immediately aborting if the thread is\n  interrupted.\n  [[Bug #14882]](https://bugs.ruby-lang.org/issues/14882)\n  [[GitHub #205]](https://github.com/ruby/openssl/pull/205)\n* Fixed OpenSSL::X509::Name#to_s failing with OpenSSL::X509::NameError if\n  called against an empty instance.\n  [[GitHub #200]](https://github.com/ruby/openssl/issues/200)\n  [[GitHub #211]](https://github.com/ruby/openssl/pull/211)\n\n\nVersion 2.0.8\n=============\n\nBug fixes\n---------\n\n* OpenSSL::Cipher#pkcs5_keyivgen raises an error when a negative iteration\n  count is given.\n  [[GitHub #184]](https://github.com/ruby/openssl/pull/184)\n* Fixed build with LibreSSL 2.7.\n  [[GitHub #192]](https://github.com/ruby/openssl/issues/192)\n  [[GitHub #193]](https://github.com/ruby/openssl/pull/193)\n\n\nVersion 2.0.7\n=============\n\nBug fixes\n---------\n\n* OpenSSL::Cipher#auth_data= could segfault if called against a non-AEAD cipher.\n  [[Bug #14024]](https://bugs.ruby-lang.org/issues/14024)\n* OpenSSL::X509::Certificate#public_key= (and similar methods) could segfault\n  when an instance of OpenSSL::PKey::PKey with no public key components is\n  passed.\n  [[Bug #14087]](https://bugs.ruby-lang.org/issues/14087)\n  [[GitHub #168]](https://github.com/ruby/openssl/pull/168)\n\n\nVersion 2.0.6\n=============\n\nBug fixes\n---------\n\n* The session_remove_cb set to an OpenSSL::SSL::SSLContext is no longer called\n  during GC.\n* A possible deadlock in OpenSSL::SSL::SSLSocket#sysread is fixed.\n  [[GitHub #139]](https://github.com/ruby/openssl/pull/139)\n* OpenSSL::BN#hash could return an unnormalized fixnum value on Windows.\n  [[Bug #13877]](https://bugs.ruby-lang.org/issues/13877)\n* OpenSSL::SSL::SSLSocket#sysread and #sysread_nonblock set the length of the\n  destination buffer String to 0 on error.\n  [[GitHub #153]](https://github.com/ruby/openssl/pull/153)\n* Possible deadlock is fixed. This happened only when built with older versions\n  of OpenSSL (before 1.1.0) or LibreSSL.\n  [[GitHub #155]](https://github.com/ruby/openssl/pull/155)\n\n\nVersion 2.0.5\n=============\n\nBug fixes\n---------\n\n* Reading a PEM/DER-encoded private key or certificate from an IO object did\n  not work properly on mswin platforms.\n  [[ruby/openssl#128]](https://github.com/ruby/openssl/issues/128)\n* Broken length check in the PEM passphrase callback is fixed.\n* It failed to compile when OpenSSL is configured without TLS 1.0 support.\n\n\nVersion 2.0.4\n=============\n\nBug fixes\n---------\n\n* It now compiles with LibreSSL without renaming on Windows (mswin).\n* A workaround for the error queue leak of X509_load_cert_crl_file() that\n  causes random errors is added.\n  [[Bug #11033]](https://bugs.ruby-lang.org/issues/11033)\n\n\nVersion 2.0.3\n=============\n\nBug fixes\n---------\n\n* OpenSSL::ASN1::Constructive#each which was broken by 2.0.0 is fixed.\n  [[ruby/openssl#96]](https://github.com/ruby/openssl/pull/96)\n* Fixed build with static OpenSSL libraries on Windows.\n  [[Bug #13080]](https://bugs.ruby-lang.org/issues/13080)\n* OpenSSL::X509::Name#eql? which was broken by 2.0.0 is fixed.\n\n\nVersion 2.0.2\n=============\n\nBug fixes\n---------\n\n* Fix build with early 0.9.8 series which did not have SSL_CTX_clear_options().\n  [ruby-core:78693]\n\n\nVersion 2.0.1\n=============\n\nBug fixes\n---------\n\n* A GC issue around OpenSSL::BN is fixed.\n  [[ruby/openssl#87]](https://github.com/ruby/openssl/issues/87)\n* OpenSSL::ASN1 now parses BER encoding of GeneralizedTime without seconds.\n  [[ruby/openssl#88]](https://github.com/ruby/openssl/pull/88)\n\n\nVersion 2.0.0\n=============\n\nThis is the first release of openssl gem, formerly a standard library of Ruby,\next/openssl. This is the successor of the version included in Ruby 2.3.\n\nCompatibility notes\n-------------------\n\n* Support for OpenSSL version 0.9.6 and 0.9.7 is completely removed. openssl gem\n  still works with OpenSSL 0.9.8, but users are strongly encouraged to upgrade\n  to at least 1.0.1, as OpenSSL < 1.0.1 will not receive any security fixes from\n  the OpenSSL development team.\n\nSupported platforms\n-------------------\n\n* OpenSSL 1.0.0, 1.0.1, 1.0.2, 1.1.0\n* OpenSSL < 0.9.8 is no longer supported.\n* LibreSSL 2.3, 2.4, 2.5\n* Ruby 2.3, 2.4\n\nNotable changes\n---------------\n\n* Add support for OpenSSL 1.1.0.\n  [[Feature #12324]](https://bugs.ruby-lang.org/issues/12324)\n* Add support for LibreSSL\n\n* OpenSSL::Cipher\n\n  - OpenSSL::Cipher#key= and #iv= reject too long inputs. They used to truncate\n    silently. [[Bug #12561]](https://bugs.ruby-lang.org/issues/12561)\n\n  - OpenSSL::Cipher#iv_len= is added. It allows changing IV (nonce) length if\n    using AEAD ciphers.\n    [[Bug #8667]](https://bugs.ruby-lang.org/issues/8667),\n    [[Bug #10420]](https://bugs.ruby-lang.org/issues/10420),\n    [[GH ruby/ruby#569]](https://github.com/ruby/ruby/pull/569),\n    [[GH ruby/openssl#58]](https://github.com/ruby/openssl/pull/58)\n\n  - OpenSSL::Cipher#auth_tag_len= is added. This sets the authentication tag\n    length to be generated by an AEAD cipher.\n\n* OpenSSL::OCSP\n\n  - Accessor methods are added to OpenSSL::OCSP::CertificateId.\n    [[Feature #7181]](https://bugs.ruby-lang.org/issues/7181)\n\n  - OpenSSL::OCSP::Request and BasicResponse can be signed with non-SHA-1 hash\n    algorithm. [[Feature #11552]](https://bugs.ruby-lang.org/issues/11552)\n\n  - OpenSSL::OCSP::CertificateId and BasicResponse can be encoded into DER.\n\n  - A new class OpenSSL::OCSP::SingleResponse is added for convenience.\n\n  - OpenSSL::OCSP::BasicResponse#add_status accepts absolute times. They used to\n    accept only relative seconds from the current time.\n\n* OpenSSL::PKey\n\n  - OpenSSL::PKey::EC follows the general PKey interface.\n    [[Bug #6567]](https://bugs.ruby-lang.org/issues/6567)\n\n  - OpenSSL::PKey.read raises OpenSSL::PKey::PKeyError instead of ArgumentError\n    for consistency with OpenSSL::PKey::{DH,DSA,RSA,EC}#new.\n    [[Bug #11774]](https://bugs.ruby-lang.org/issues/11774),\n    [[GH ruby/openssl#55]](https://github.com/ruby/openssl/pull/55)\n\n  - OpenSSL::PKey::EC::Group retrieved by OpenSSL::PKey::EC#group is no longer\n    linked with the EC key. Modifications to the EC::Group have no effect on the\n    key. [[GH ruby/openssl#71]](https://github.com/ruby/openssl/pull/71)\n\n  - OpenSSL::PKey::EC::Point#to_bn allows specifying the point conversion form\n    by the optional argument.\n\n* OpenSSL::SSL\n\n  - OpenSSL::SSL::SSLSocket#tmp_key is added. A client can call it after the\n    connection is established to retrieve the ephemeral key.\n    [[GH ruby/ruby#1318]](https://github.com/ruby/ruby/pull/1318)\n\n  - The automatic ephemeral ECDH curve selection is enabled by default when\n    built with OpenSSL >= 1.0.2 or LibreSSL.\n\n  - OpenSSL::SSL::SSLContext#security_level= is added. You can set the \"security\n    level\" of the SSL context. This is effective only when built with OpenSSL\n    1.1.0.\n\n  - A new option 'verify_hostname' is added to OpenSSL::SSL::SSLContext. When it\n    is enabled, and the SNI hostname is also set, the hostname verification on\n    the server certificate is automatically performed. It is now enabled by\n    OpenSSL::SSL::SSLContext#set_params.\n    [[GH ruby/openssl#60]](https://github.com/ruby/openssl/pull/60)\n\nRemovals\n--------\n\n* OpenSSL::Engine\n\n  - OpenSSL::Engine.cleanup does nothing when built with OpenSSL 1.1.0.\n\n* OpenSSL::SSL\n\n  - OpenSSL::PKey::DH::DEFAULT_512 is removed. Hence servers no longer use\n    512-bit DH group by default. It is considered too weak nowadays.\n    [[Bug #11968]](https://bugs.ruby-lang.org/issues/11968),\n    [[GH ruby/ruby#1196]](https://github.com/ruby/ruby/pull/1196)\n\n  - RC4 cipher suites are removed from OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.\n    RC4 is now considered to be weak.\n    [[GH ruby/openssl#50]](https://github.com/ruby/openssl/pull/50)\n\nDeprecations\n------------\n\n* OpenSSL::PKey\n\n  - OpenSSL::PKey::RSA#n=, #e=, #d=, #p=, #q=, #dmp1=, #dmq1=, #iqmp=,\n    OpenSSL::PKey::DSA#p=, #q=, #g=, #priv_key=, #pub_key=,\n    OpenSSL::PKey::DH#p=, #g=, #priv_key= and #pub_key= are deprecated. They are\n    disabled when built with OpenSSL 1.1.0, due to its API change. Instead,\n    OpenSSL::PKey::RSA#set_key, #set_factors, #set_crt_params,\n    OpenSSL::PKey::DSA#set_pqg, #set_key, OpenSSL::PKey::DH#set_pqg and #set_key\n    are added.\n\n* OpenSSL::Random\n\n  - OpenSSL::Random.pseudo_bytes is deprecated, and not defined when built with\n    OpenSSL 1.1.0. Use OpenSSL::Random.random_bytes instead.\n\n* OpenSSL::SSL\n\n  - OpenSSL::SSL::SSLContext#tmp_ecdh_callback is deprecated, as the underlying\n    API SSL_CTX_set_tmp_ecdh_callback() is removed in OpenSSL 1.1.0. It was\n    first added in Ruby 2.3.0. To specify the curve to be used in ephemeral\n    ECDH, use OpenSSL::SSL::SSLContext#ecdh_curves=. The automatic curve\n    selection is also now enabled by default when built with a capable OpenSSL.\n"
  },
  {
    "path": "README.md",
    "content": "# OpenSSL for Ruby\n\n[![Actions Status](https://github.com/ruby/openssl/workflows/CI/badge.svg)](https://github.com/ruby/openssl/actions?workflow=CI)\n\n**OpenSSL for Ruby** provides access to SSL/TLS and general-purpose\ncryptography based on the OpenSSL library.\n\nOpenSSL for Ruby is sometimes referred to as **openssl** in all lowercase\nor **Ruby/OpenSSL** for disambiguation.\n\n## Compatibility and maintenance policy\n\nOpenSSL for Ruby is released as a RubyGems gem. At the same time, it is part of\nthe standard library of Ruby. This is called a [default gem].\n\nEach stable branch of OpenSSL for Ruby will remain supported as long as it is\nincluded as a default gem in [supported Ruby branches][Ruby Maintenance Branches].\n\n|Version|Minimum Ruby|OpenSSL compatibility                    |Bundled with|Maintenance  |\n|-------|------------|-----------------------------------------|------------|-------------|\n|4.0.x  |Ruby 2.7    |OpenSSL 1.1.1-3.x, LibreSSL 3.9+, AWS-LC |Ruby 4.0    |bug fixes    |\n|3.3.x  |Ruby 2.7    |OpenSSL 1.0.2-3.x, LibreSSL 3.1+         |Ruby 3.4    |bug fixes    |\n|3.2.x  |Ruby 2.7    |OpenSSL 1.0.2-3.x, LibreSSL 3.1+         |Ruby 3.3    |bug fixes    |\n|3.1.x  |Ruby 2.6    |OpenSSL 1.0.2-3.x, LibreSSL 3.1+         |Ruby 3.2    |security only|\n|3.0.x  |Ruby 2.6    |OpenSSL 1.0.2-3.x, LibreSSL 3.1+         |Ruby 3.1    |end-of-life  |\n|2.2.x  |Ruby 2.3    |OpenSSL 1.0.1-1.1.1, LibreSSL 2.9+       |Ruby 3.0    |end-of-life  |\n|2.1.x  |Ruby 2.3    |OpenSSL 1.0.1-1.1.1, LibreSSL 2.5+       |Ruby 2.5-2.7|end-of-life  |\n|2.0.x  |Ruby 2.3    |OpenSSL 0.9.8-1.1.1, LibreSSL 2.3+       |Ruby 2.4    |end-of-life  |\n\n[default gem]: https://docs.ruby-lang.org/en/master/standard_library_md.html\n[Ruby Maintenance Branches]: https://www.ruby-lang.org/en/downloads/branches/\n\n## Installation\n\n> **Note**\n> The openssl gem is included with Ruby by default, but you may wish to upgrade\n> it to a newer version available at [rubygems.org][RubyGems.org openssl].\n\nTo upgrade it, you can use RubyGems:\n\n```\ngem install openssl\n```\n\nIn some cases, it may be necessary to specify the path to the installation\ndirectory of the OpenSSL library.\n\n```\ngem install openssl -- --with-openssl-dir=/opt/openssl\n```\n\nAlternatively, you can install the gem with Bundler:\n\n```ruby\n# Gemfile\ngem 'openssl'\n# or specify git master\ngem 'openssl', git: 'https://github.com/ruby/openssl'\n```\n\nAfter running `bundle install`, you should have the gem installed in your bundle.\n\n[RubyGems.org openssl]: https://rubygems.org/gems/openssl\n\n## Usage\n\nOnce installed, you can require \"openssl\" in your application.\n\n```ruby\nrequire \"openssl\"\n```\n\n## Documentation\n\nSee https://ruby.github.io/openssl/.\n\n## Contributing\n\nPlease read our [CONTRIBUTING.md] for instructions.\n\n[CONTRIBUTING.md]: https://github.com/ruby/openssl/tree/master/CONTRIBUTING.md\n\n## Security\n\nSecurity issues should be reported to ruby-core by following the process\ndescribed on [\"Security at ruby-lang.org\"][Security].\n\n[Security]: https://www.ruby-lang.org/en/security/\n"
  },
  {
    "path": "Rakefile",
    "content": "require 'rake/testtask'\nrequire 'rdoc/task'\nrequire 'bundler/gem_tasks'\n\nbegin\n  require 'rake/extensiontask'\n  Rake::ExtensionTask.new('openssl')\nrescue LoadError\n  warn \"rake-compiler not installed. Run 'bundle install' to \" \\\n    \"install testing dependency gems.\"\nend\n\ntask :test => :compile\nRake::TestTask.new do |t|\n  t.test_files = FileList[\"test/**/test_*.rb\"]\n  t.warning = true\nend\n\ndesc 'Run tests for fips'\ntask :test_fips => :compile do\n  ENV['TEST_RUBY_OPENSSL_FIPS_ENABLED'] = 'true'\n  Rake::Task['test_fips_internal'].invoke\nend\n\nRake::TestTask.new(:test_fips_internal) do |t|\n  # Exclude failing test files in FIPS for this task to pass.\n  # TODO: Fix failing test files.\n  t.test_files = FileList['test/**/test_*.rb'] - FileList[\n    'test/openssl/test_hmac.rb',\n    'test/openssl/test_kdf.rb',\n    'test/openssl/test_ts.rb',\n  ]\n  t.warning = true\nend\n\nRDoc::Task.new do |rdoc|\n  rdoc.main = \"README.md\"\n  rdoc.rdoc_files.include(\"*.md\", \"lib/**/*.rb\", \"ext/**/*.c\")\nend\n\n# Print Ruby and compiler info for debugging purpose.\ntask :debug_compiler do\n  compiler = RbConfig::CONFIG['CC']\n  case compiler\n  when 'gcc', 'clang'\n    sh \"#{compiler} --version\"\n  else\n    Rake.rake_output_message \"Compiler: #{RbConfig::CONFIG['CC']}\"\n  end\nend\n\ntask :debug do\n  ruby_code = <<~'EOF'\n    openssl_version_number_str = OpenSSL::OPENSSL_VERSION_NUMBER.to_s(16)\n    libressl_version_number_str = (defined? OpenSSL::LIBRESSL_VERSION_NUMBER) ?\n      OpenSSL::LIBRESSL_VERSION_NUMBER.to_s(16) : \"undefined\"\n    providers_str = (defined? OpenSSL::Provider) ?\n      OpenSSL::Provider.provider_names.join(\", \") : \"undefined\"\n    puts <<~MESSAGE\n      OpenSSL::OPENSSL_VERSION: #{OpenSSL::OPENSSL_VERSION}\n      OpenSSL::OPENSSL_LIBRARY_VERSION: #{OpenSSL::OPENSSL_LIBRARY_VERSION}\n      OpenSSL::OPENSSL_VERSION_NUMBER: #{openssl_version_number_str}\n      OpenSSL::LIBRESSL_VERSION_NUMBER: #{libressl_version_number_str}\n      FIPS enabled: #{OpenSSL.fips_mode}\n      Providers: #{providers_str}\n    MESSAGE\n  EOF\n  ruby %Q(-I./lib -ropenssl.so -e'#{ruby_code}'), verbose: false\nend\n\ntask :default => :test\n"
  },
  {
    "path": "ext/openssl/extconf.rb",
    "content": "# -*- coding: us-ascii -*-\n# frozen_string_literal: true\n=begin\n= Info\n  'OpenSSL for Ruby 2' project\n  Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>\n  All rights reserved.\n\n= Licence\n  This program is licensed under the same licence as Ruby.\n  (See the file 'COPYING'.)\n=end\n\nrequire \"mkmf\"\n\nssl_dirs = dir_config(\"openssl\")\ndir_config_given = ssl_dirs.any?\n\n_, ssl_ldir = ssl_dirs\nif ssl_ldir&.split(File::PATH_SEPARATOR)&.none? { |dir| File.directory?(dir) }\n  # According to the `mkmf.rb#dir_config`, the `--with-openssl-dir=<dir>` uses\n  # the value of the `File.basename(RbConfig::MAKEFILE_CONFIG[\"libdir\"])` as a\n  # loaded library directory name.\n  ruby_ldir_name = File.basename(RbConfig::MAKEFILE_CONFIG[\"libdir\"])\n\n  raise \"OpenSSL library directory could not be found in '#{ssl_ldir}'. \" \\\n    \"You might want to fix this error in one of the following ways.\\n\" \\\n    \"  * Recompile OpenSSL by configuring it with --libdir=#{ruby_ldir_name} \" \\\n    \" to specify the OpenSSL library directory.\\n\" \\\n    \"  * Recompile Ruby by configuring it with --libdir=<dir> to specify the \" \\\n    \"Ruby library directory.\\n\" \\\n    \"  * Compile this openssl gem with --with-openssl-include=<dir> and \" \\\n    \"--with-openssl-lib=<dir> options to specify the OpenSSL include and \" \\\n    \"library directories.\"\nend\n\nLogging::message \"=== OpenSSL for Ruby configurator ===\\n\"\n\n$defs.push(\"-D\"\"OPENSSL_SUPPRESS_DEPRECATED\")\n\n# Missing in TruffleRuby\nhave_func(\"rb_call_super_kw(0, NULL, 0)\", \"ruby.h\")\n# Ruby 3.1\nhave_func(\"rb_io_descriptor\", \"ruby/io.h\")\nhave_func(\"rb_io_maybe_wait(0, Qnil, Qnil, Qnil)\", \"ruby/io.h\")\n# Ruby 3.2\nhave_func(\"rb_io_timeout\", \"ruby/io.h\")\n\nLogging::message \"=== Checking for system dependent stuff... ===\\n\"\nhave_library(\"nsl\", \"t_open\")\nhave_library(\"socket\", \"socket\")\nif $mswin || $mingw\n  have_library(\"ws2_32\")\nend\n\nif $mingw\n  append_cflags '-D_FORTIFY_SOURCE=2'\n  append_ldflags '-fstack-protector'\n  have_library 'ssp'\nend\n\ndef find_openssl_library\n  if $mswin || $mingw\n    # required for static OpenSSL libraries\n    have_library(\"crypt32\")\n  end\n\n  return false unless have_header(\"openssl/ssl.h\")\n\n  ret = have_library(\"crypto\", \"CRYPTO_malloc\") &&\n    have_library(\"ssl\", \"SSL_new\")\n  return ret if ret\n\n  if $mswin\n    # OpenSSL >= 1.1.0: libcrypto.lib and libssl.lib.\n    if have_library(\"libcrypto\", \"CRYPTO_malloc\") &&\n        have_library(\"libssl\", \"SSL_new\")\n      return true\n    end\n\n    # LibreSSL: libcrypto-##.lib and libssl-##.lib, where ## is the ABI version\n    # number. We have to find the version number out by scanning libpath.\n    libpath = $LIBPATH.dup\n    libpath |= ENV[\"LIB\"].split(File::PATH_SEPARATOR)\n    libpath.map! { |d| d.tr(File::ALT_SEPARATOR, File::SEPARATOR) }\n\n    ret = [\n      [\"crypto\", \"CRYPTO_malloc\"],\n      [\"ssl\", \"SSL_new\"]\n    ].all? do |base, func|\n      result = false\n      libs = [\"lib#{base}-[0-9][0-9]\", \"lib#{base}-[0-9][0-9][0-9]\"]\n      libs = Dir.glob(libs.map{|l| libpath.map{|d| File.join(d, l + \".*\")}}.flatten).map{|path| File.basename(path, \".*\")}.uniq\n      libs.each do |lib|\n        result = have_library(lib, func)\n        break if result\n      end\n      result\n    end\n    return ret if ret\n  end\n  return false\nend\n\nLogging::message \"=== Checking for required stuff... ===\\n\"\npkg_config_found = !dir_config_given && pkg_config(\"openssl\") && have_header(\"openssl/ssl.h\")\n\nif !pkg_config_found && !find_openssl_library\n  Logging::message \"=== Checking for required stuff failed. ===\\n\"\n  Logging::message \"Makefile wasn't created. Fix the errors above.\\n\"\n  raise \"OpenSSL library could not be found. You might want to use \" \\\n    \"--with-openssl-dir=<dir> option to specify the prefix where OpenSSL \" \\\n    \"is installed.\"\nend\n\nversion_ok = if have_macro(\"LIBRESSL_VERSION_NUMBER\", \"openssl/opensslv.h\")\n  is_libressl = true\n  checking_for(\"LibreSSL version >= 3.9.0\") {\n    try_static_assert(\"LIBRESSL_VERSION_NUMBER >= 0x30900000L\", \"openssl/opensslv.h\") }\nelse\n  is_openssl = true\n  checking_for(\"OpenSSL version >= 1.1.1\") {\n    try_static_assert(\"OPENSSL_VERSION_NUMBER >= 0x10101000L\", \"openssl/opensslv.h\") }\nend\nunless version_ok\n  raise \"OpenSSL >= 1.1.1 or LibreSSL >= 3.9.0 is required\"\nend\n\n# Prevent wincrypt.h from being included, which defines conflicting macro with openssl/x509.h\nif is_libressl && ($mswin || $mingw)\n  $defs.push(\"-DNOCRYPT\")\nend\n\nLogging::message \"=== Checking for OpenSSL features... ===\\n\"\nevp_h = \"openssl/evp.h\".freeze\nts_h = \"openssl/ts.h\".freeze\nssl_h = \"openssl/ssl.h\".freeze\n\n# compile options\nhave_func(\"RAND_egd()\", \"openssl/rand.h\")\n\n# added in OpenSSL 1.0.2, not in LibreSSL yet\nhave_func(\"SSL_CTX_set1_sigalgs_list(NULL, NULL)\", ssl_h)\n# added in OpenSSL 1.0.2, not in LibreSSL or AWS-LC yet\nhave_func(\"SSL_CTX_set1_client_sigalgs_list(NULL, NULL)\", ssl_h)\n\n# added in 1.1.0, currently not in LibreSSL\nhave_func(\"EVP_PBE_scrypt(\\\"\\\", 0, (unsigned char *)\\\"\\\", 0, 0, 0, 0, 0, NULL, 0)\", evp_h)\n\n# added in OpenSSL 1.1.1 and LibreSSL 3.5.0, then removed in LibreSSL 4.0.0\nhave_func(\"EVP_PKEY_check(NULL)\", evp_h)\n\n# added in 3.0.0\nhave_func(\"SSL_CTX_set0_tmp_dh_pkey(NULL, NULL)\", ssl_h)\nhave_func(\"ERR_get_error_all(NULL, NULL, NULL, NULL, NULL)\", \"openssl/err.h\")\nhave_func(\"SSL_CTX_load_verify_file(NULL, \\\"\\\")\", ssl_h)\nhave_func(\"BN_check_prime(NULL, NULL, NULL)\", \"openssl/bn.h\")\nhave_func(\"EVP_MD_CTX_get0_md(NULL)\", evp_h)\nhave_func(\"EVP_MD_CTX_get_pkey_ctx(NULL)\", evp_h)\nhave_func(\"EVP_PKEY_eq(NULL, NULL)\", evp_h)\nhave_func(\"EVP_PKEY_dup(NULL)\", evp_h)\n\n# added in 3.2.0\nhave_func(\"SSL_get0_group_name(NULL)\", ssl_h)\n\n# added in 3.4.0\nhave_func(\"TS_VERIFY_CTX_set0_certs(NULL, NULL)\", ts_h)\n\n# added in 3.5.0\nhave_func(\"SSL_get0_peer_signature_name(NULL, NULL)\", ssl_h)\n\n# added in 4.0.0\nhave_func(\"ASN1_BIT_STRING_set1(NULL, NULL, 0, 0)\", \"openssl/asn1.h\")\n\nLogging::message \"=== Checking done. ===\\n\"\n\n# Append flags from environment variables.\nextcflags = ENV[\"RUBY_OPENSSL_EXTCFLAGS\"]\nappend_cflags(extcflags.split) if extcflags\nextldflags = ENV[\"RUBY_OPENSSL_EXTLDFLAGS\"]\nappend_ldflags(extldflags.split) if extldflags\n\ncreate_header\ncreate_makefile(\"openssl\")\nLogging::message \"Done.\\n\"\n"
  },
  {
    "path": "ext/openssl/openssl_missing.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_OPENSSL_MISSING_H_)\n#define _OSSL_OPENSSL_MISSING_H_\n\n#include \"ruby/config.h\"\n\n/* added in 3.0.0 */\n#ifndef HAVE_EVP_MD_CTX_GET0_MD\n#  define EVP_MD_CTX_get0_md(ctx) EVP_MD_CTX_md(ctx)\n#endif\n\n/*\n * OpenSSL 1.1.0 added EVP_MD_CTX_pkey_ctx(), and then it was renamed to\n * EVP_MD_CTX_get_pkey_ctx(x) in OpenSSL 3.0.\n */\n#ifndef HAVE_EVP_MD_CTX_GET_PKEY_CTX\n#  define EVP_MD_CTX_get_pkey_ctx(x) EVP_MD_CTX_pkey_ctx(x)\n#endif\n\n#ifndef HAVE_EVP_PKEY_EQ\n#  define EVP_PKEY_eq(a, b) EVP_PKEY_cmp(a, b)\n#endif\n\n/* added in 4.0.0 */\n#ifndef HAVE_ASN1_BIT_STRING_SET1\nstatic inline int\nASN1_BIT_STRING_set1(ASN1_BIT_STRING *bitstr, const uint8_t *data,\n                     size_t length, int unused_bits)\n{\n    if (length > INT_MAX || !ASN1_STRING_set(bitstr, data, (int)length))\n        return 0;\n    bitstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);\n    bitstr->flags |= ASN1_STRING_FLAG_BITS_LEFT | unused_bits;\n    return 1;\n}\n\nstatic inline int\nASN1_BIT_STRING_get_length(const ASN1_BIT_STRING *bitstr, size_t *length,\n                           int *unused_bits)\n{\n    *length = bitstr->length;\n    *unused_bits = bitstr->flags & 0x07;\n    return 1;\n}\n#endif\n\n#endif /* _OSSL_OPENSSL_MISSING_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n#include <stdarg.h> /* for ossl_raise */\n\n/*\n * Data Conversion\n */\n#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup)       \\\nVALUE                                                           \\\nossl_##name##_ary2sk0(VALUE ary)                                \\\n{                                                               \\\n    STACK_OF(type) *sk;                                         \\\n    VALUE val;                                                  \\\n    type *x;                                                    \\\n    int i;                                                      \\\n                                                                \\\n    Check_Type(ary, T_ARRAY);                                   \\\n    sk = sk_##type##_new_null();                                \\\n    if (!sk) ossl_raise(eOSSLError, NULL);                      \\\n                                                                \\\n    for (i = 0; i < RARRAY_LEN(ary); i++) {                     \\\n        val = rb_ary_entry(ary, i);                             \\\n        if (!rb_obj_is_kind_of(val, expected_class)) {          \\\n            sk_##type##_pop_free(sk, type##_free);              \\\n            ossl_raise(eOSSLError, \"object in array not\"        \\\n                       \" of class ##type##\");                   \\\n        }                                                       \\\n        x = dup(val); /* NEED TO DUP */                         \\\n        if (!sk_##type##_push(sk, x)) {                         \\\n            type##_free(x);                                     \\\n            sk_##type##_pop_free(sk, type##_free);              \\\n            ossl_raise(eOSSLError, NULL);                       \\\n        }                                                       \\\n    }                                                           \\\n    return (VALUE)sk;                                           \\\n}                                                               \\\n                                                                \\\nSTACK_OF(type) *                                                \\\nossl_protect_##name##_ary2sk(VALUE ary, int *status)            \\\n{                                                               \\\n    return (STACK_OF(type)*)rb_protect(                         \\\n            (VALUE (*)(VALUE))ossl_##name##_ary2sk0,            \\\n            ary,                                                \\\n            status);                                            \\\n}                                                               \\\n                                                                \\\nSTACK_OF(type) *                                                \\\nossl_##name##_ary2sk(VALUE ary)                                 \\\n{                                                               \\\n    STACK_OF(type) *sk;                                         \\\n    int status = 0;                                             \\\n                                                                \\\n    sk = ossl_protect_##name##_ary2sk(ary, &status);            \\\n    if (status) rb_jump_tag(status);                            \\\n                                                                \\\n    return sk;                                                  \\\n}\nOSSL_IMPL_ARY2SK(x509, X509, cX509Cert, DupX509CertPtr)\n\n#define OSSL_IMPL_SK2ARY(name, type)            \\\nVALUE                                           \\\nossl_##name##_sk2ary(const STACK_OF(type) *sk)  \\\n{                                               \\\n    type *t;                                    \\\n    int i, num;                                 \\\n    VALUE ary;                                  \\\n                                                \\\n    RUBY_ASSERT(sk != NULL);                    \\\n    num = sk_##type##_num(sk);                  \\\n    ary = rb_ary_new_capa(num);                 \\\n                                                \\\n    for (i=0; i<num; i++) {                     \\\n        t = sk_##type##_value(sk, i);           \\\n        rb_ary_push(ary, ossl_##name##_new(t)); \\\n    }                                           \\\n    return ary;                                 \\\n}\nOSSL_IMPL_SK2ARY(x509, X509)\nOSSL_IMPL_SK2ARY(x509crl, X509_CRL)\nOSSL_IMPL_SK2ARY(x509name, X509_NAME)\n\nstatic VALUE\nossl_str_new_i(VALUE size)\n{\n    return rb_str_new(NULL, (long)size);\n}\n\nVALUE\nossl_str_new(const char *ptr, long len, int *pstate)\n{\n    VALUE str;\n    int state;\n\n    str = rb_protect(ossl_str_new_i, len, &state);\n    if (pstate)\n        *pstate = state;\n    if (state) {\n        if (!pstate)\n            rb_set_errinfo(Qnil);\n        return Qnil;\n    }\n    if (ptr)\n        memcpy(RSTRING_PTR(str), ptr, len);\n    return str;\n}\n\nVALUE\nossl_buf2str(char *buf, int len)\n{\n    VALUE str;\n    int state;\n\n    str = ossl_str_new(buf, len, &state);\n    OPENSSL_free(buf);\n    if (state)\n        rb_jump_tag(state);\n    return str;\n}\n\nvoid\nossl_bin2hex(const unsigned char *in, char *out, size_t inlen)\n{\n    const char *hex = \"0123456789abcdef\";\n    size_t i;\n\n    assert(inlen <= LONG_MAX / 2);\n    for (i = 0; i < inlen; i++) {\n        unsigned char p = in[i];\n\n        out[i * 2 + 0] = hex[p >> 4];\n        out[i * 2 + 1] = hex[p & 0x0f];\n    }\n}\n\n/*\n * our default PEM callback\n */\nVALUE\nossl_pem_passwd_value(VALUE pass)\n{\n    if (NIL_P(pass))\n        return Qnil;\n\n    StringValue(pass);\n\n    /* PEM_BUFSIZE is currently used as the second argument of pem_password_cb,\n     * that is +max_len+ of ossl_pem_passwd_cb() */\n    if (RSTRING_LEN(pass) > PEM_BUFSIZE)\n        ossl_raise(eOSSLError, \"password must not be longer than %d bytes\", PEM_BUFSIZE);\n\n    return pass;\n}\n\nstatic VALUE\nossl_pem_passwd_cb0(VALUE flag)\n{\n    VALUE pass = rb_yield(flag);\n    if (NIL_P(pass))\n        return Qnil;\n    StringValue(pass);\n    return pass;\n}\n\nint\nossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)\n{\n    long len;\n    int status;\n    VALUE rflag, pass = (VALUE)pwd_;\n\n    if (RTEST(pass)) {\n        /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not\n         * work because it does not allow NUL characters and truncates to 1024\n         * bytes silently if the input is over 1024 bytes */\n        if (RB_TYPE_P(pass, T_STRING)) {\n            len = RSTRING_LEN(pass);\n            if (len <= max_len) {\n                memcpy(buf, RSTRING_PTR(pass), len);\n                return (int)len;\n            }\n        }\n        OSSL_Debug(\"passed data is not valid String???\");\n        return -1;\n    }\n\n    if (!rb_block_given_p()) {\n        return PEM_def_callback(buf, max_len, flag, NULL);\n    }\n\n    while (1) {\n        /*\n         * when the flag is nonzero, this password\n         * will be used to perform encryption; otherwise it will\n         * be used to perform decryption.\n         */\n        rflag = flag ? Qtrue : Qfalse;\n        pass  = rb_protect(ossl_pem_passwd_cb0, rflag, &status);\n        if (status) {\n            /* ignore an exception raised. */\n            rb_set_errinfo(Qnil);\n            return -1;\n        }\n        if (NIL_P(pass))\n            return -1;\n        len = RSTRING_LEN(pass);\n        if (len > max_len) {\n            rb_warning(\"password must not be longer than %d bytes\", max_len);\n            continue;\n        }\n        memcpy(buf, RSTRING_PTR(pass), len);\n        break;\n    }\n    return (int)len;\n}\n\n/*\n * main module\n */\nVALUE mOSSL;\n\n/*\n * OpenSSLError < StandardError\n */\nVALUE eOSSLError;\n\n/*\n * Convert to DER string\n */\nstatic ID ossl_s_to_der;\n\nVALUE\nossl_to_der(VALUE obj)\n{\n    VALUE tmp;\n\n    tmp = rb_funcall(obj, ossl_s_to_der, 0);\n    StringValue(tmp);\n\n    return tmp;\n}\n\nVALUE\nossl_to_der_if_possible(VALUE obj)\n{\n    if(rb_respond_to(obj, ossl_s_to_der))\n        return ossl_to_der(obj);\n    return obj;\n}\n\n/*\n * Errors\n */\nstatic ID id_i_errors;\n\nstatic void collect_errors_into(VALUE ary);\n\nVALUE\nossl_make_error(VALUE exc, VALUE str)\n{\n    unsigned long e;\n    const char *data;\n    int flags;\n    VALUE errors = rb_ary_new();\n\n    if (NIL_P(str))\n        str = rb_str_new(NULL, 0);\n\n#ifdef HAVE_ERR_GET_ERROR_ALL\n    e = ERR_peek_last_error_all(NULL, NULL, NULL, &data, &flags);\n#else\n    e = ERR_peek_last_error_line_data(NULL, NULL, &data, &flags);\n#endif\n    if (e) {\n        const char *msg = ERR_reason_error_string(e);\n\n        if (RSTRING_LEN(str)) rb_str_cat_cstr(str, \": \");\n        rb_str_cat_cstr(str, msg ? msg : \"(null)\");\n        if (flags & ERR_TXT_STRING && data)\n            rb_str_catf(str, \" (%s)\", data);\n        collect_errors_into(errors);\n    }\n\n    VALUE obj = rb_exc_new_str(exc, str);\n    rb_ivar_set(obj, id_i_errors, errors);\n    return obj;\n}\n\nvoid\nossl_raise(VALUE exc, const char *fmt, ...)\n{\n    va_list args;\n    VALUE err;\n\n    if (fmt) {\n        va_start(args, fmt);\n        err = rb_vsprintf(fmt, args);\n        va_end(args);\n    }\n    else {\n        err = Qnil;\n    }\n\n    rb_exc_raise(ossl_make_error(exc, err));\n}\n\nstatic void\ncollect_errors_into(VALUE ary)\n{\n    if (dOSSL == Qtrue || !NIL_P(ary)) {\n        unsigned long e;\n        const char *file, *data, *func, *lib, *reason;\n        int line, flags;\n\n#ifdef HAVE_ERR_GET_ERROR_ALL\n        while ((e = ERR_get_error_all(&file, &line, &func, &data, &flags))) {\n#else\n        while ((e = ERR_get_error_line_data(&file, &line, &data, &flags))) {\n            func = ERR_func_error_string(e);\n#endif\n            lib = ERR_lib_error_string(e);\n            reason = ERR_reason_error_string(e);\n\n            VALUE str = rb_sprintf(\"error:%08lX:%s:%s:%s\", e, lib ? lib : \"\",\n                                   func ? func : \"\", reason ? reason : \"\");\n            if (flags & ERR_TXT_STRING) {\n                if (!data)\n                    data = \"(null)\";\n                rb_str_catf(str, \" (%s)\", data);\n            }\n\n            if (dOSSL == Qtrue)\n                rb_warn(\"error on stack: %\"PRIsVALUE, str);\n            if (!NIL_P(ary))\n                rb_ary_push(ary, str);\n        }\n    }\n    else {\n        ERR_clear_error();\n    }\n}\n\nvoid\nossl_clear_error(void)\n{\n    collect_errors_into(Qnil);\n}\n\n/*\n * call-seq:\n *    ossl_error.detailed_message(**) -> string\n *\n * Returns the exception message decorated with the captured \\OpenSSL error\n * queue entries.\n */\nstatic VALUE\nosslerror_detailed_message(int argc, VALUE *argv, VALUE self)\n{\n    VALUE str;\n#ifdef HAVE_RB_CALL_SUPER_KW\n    // Ruby >= 3.2\n    if (RTEST(rb_funcall(rb_eException, rb_intern(\"method_defined?\"), 1,\n                         ID2SYM(rb_intern(\"detailed_message\")))))\n        str = rb_call_super_kw(argc, argv, RB_PASS_CALLED_KEYWORDS);\n    else\n#endif\n        str = rb_funcall(self, rb_intern(\"message\"), 0);\n    VALUE errors = rb_attr_get(self, id_i_errors);\n\n    // OpenSSLError was not created by ossl_make_error()\n    if (!RB_TYPE_P(errors, T_ARRAY))\n        return str;\n\n    str = rb_str_resurrect(str);\n    rb_str_catf(str, \"\\nOpenSSL error queue reported %ld errors:\",\n                RARRAY_LEN(errors));\n    for (long i = 0; i < RARRAY_LEN(errors); i++) {\n        VALUE err = RARRAY_AREF(errors, i);\n        rb_str_catf(str, \"\\n%\"PRIsVALUE, err);\n    }\n    return str;\n}\n\n/*\n * call-seq:\n *   OpenSSL.errors -> [String...]\n *\n * Returns any remaining errors held in the \\OpenSSL thread-local error queue\n * and clears the queue. This should normally return an empty array.\n *\n * This is intended for debugging Ruby/OpenSSL. If you see any errors here,\n * it likely indicates a bug in the extension. Please file an issue at\n * https://github.com/ruby/openssl.\n *\n * For debugging your program, OpenSSL.debug= may be useful.\n */\nstatic VALUE\nossl_get_errors(VALUE _)\n{\n    VALUE ary;\n    long e;\n\n    ary = rb_ary_new();\n    while ((e = ERR_get_error()) != 0){\n        rb_ary_push(ary, rb_str_new2(ERR_error_string(e, NULL)));\n    }\n\n    return ary;\n}\n\n/*\n * Debug\n */\nVALUE dOSSL;\n\n/*\n * call-seq:\n *   OpenSSL.debug -> true | false\n *\n * Returns whether Ruby/OpenSSL's debug mode is currently enabled.\n */\nstatic VALUE\nossl_debug_get(VALUE self)\n{\n    return dOSSL;\n}\n\n/*\n * call-seq:\n *   OpenSSL.debug = boolean\n *\n * Turns on or off debug mode. With debug mode, all errors added to the \\OpenSSL\n * error queue will be printed to stderr.\n */\nstatic VALUE\nossl_debug_set(VALUE self, VALUE val)\n{\n    dOSSL = RTEST(val) ? Qtrue : Qfalse;\n\n    return val;\n}\n\n/*\n * call-seq:\n *   OpenSSL.fips_mode -> true | false\n *\n * Returns whether the FIPS mode is currently enabled.\n */\nstatic VALUE\nossl_fips_mode_get(VALUE self)\n{\n\n#if OSSL_OPENSSL_PREREQ(3, 0, 0)\n    VALUE enabled;\n    enabled = EVP_default_properties_is_fips_enabled(NULL) ? Qtrue : Qfalse;\n    return enabled;\n#elif defined(OPENSSL_FIPS) || defined(OPENSSL_IS_AWSLC)\n    VALUE enabled;\n    enabled = FIPS_mode() ? Qtrue : Qfalse;\n    return enabled;\n#else\n    return Qfalse;\n#endif\n}\n\n/*\n * call-seq:\n *   OpenSSL.fips_mode = boolean\n *\n * Turns FIPS mode on or off. Turning on FIPS mode will obviously only have an\n * effect for FIPS-capable installations of the \\OpenSSL library. Trying to do\n * so otherwise will result in an error.\n *\n * === Examples\n *   OpenSSL.fips_mode = true   # turn FIPS mode on\n *   OpenSSL.fips_mode = false  # and off again\n */\nstatic VALUE\nossl_fips_mode_set(VALUE self, VALUE enabled)\n{\n#if OSSL_OPENSSL_PREREQ(3, 0, 0)\n    if (RTEST(enabled)) {\n        if (!EVP_default_properties_enable_fips(NULL, 1)) {\n            ossl_raise(eOSSLError, \"Turning on FIPS mode failed\");\n        }\n    } else {\n        if (!EVP_default_properties_enable_fips(NULL, 0)) {\n            ossl_raise(eOSSLError, \"Turning off FIPS mode failed\");\n        }\n    }\n    return enabled;\n#elif defined(OPENSSL_FIPS) || defined(OPENSSL_IS_AWSLC)\n    if (RTEST(enabled)) {\n        int mode = FIPS_mode();\n        if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */\n            ossl_raise(eOSSLError, \"Turning on FIPS mode failed\");\n    } else {\n        if(!FIPS_mode_set(0)) /* turning off twice is OK */\n            ossl_raise(eOSSLError, \"Turning off FIPS mode failed\");\n    }\n    return enabled;\n#else\n    if (RTEST(enabled))\n        ossl_raise(eOSSLError, \"This version of OpenSSL does not support FIPS mode\");\n    return enabled;\n#endif\n}\n\n/*\n * call-seq:\n *   OpenSSL.fixed_length_secure_compare(string, string) -> true or false\n *\n * Constant time memory comparison for fixed length strings, such as results\n * of \\HMAC calculations.\n *\n * Returns +true+ if the strings are identical, +false+ if they are of the same\n * length but not identical. If the length is different, ArgumentError is\n * raised.\n */\nstatic VALUE\nossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)\n{\n    const unsigned char *p1;\n    const unsigned char *p2;\n    long len1;\n    long len2;\n\n    StringValue(str1);\n    StringValue(str2);\n\n    p1 = (const unsigned char *)RSTRING_PTR(str1);\n    p2 = (const unsigned char *)RSTRING_PTR(str2);\n    len1 = RSTRING_LEN(str1);\n    len2 = RSTRING_LEN(str2);\n\n    if (len1 != len2) {\n        ossl_raise(rb_eArgError, \"inputs must be of equal length\");\n    }\n\n    switch (CRYPTO_memcmp(p1, p2, len1)) {\n      case 0: return Qtrue;\n      default: return Qfalse;\n    }\n}\n\n/*\n * OpenSSL provides \\SSL, TLS and general purpose cryptography.  It wraps the\n * OpenSSL[https://www.openssl.org/] library.\n *\n * = Examples\n *\n * All examples assume you have loaded OpenSSL with:\n *\n *   require 'openssl'\n *\n * These examples build atop each other.  For example the key created in the\n * next is used in throughout these examples.\n *\n * == Keys\n *\n * === Creating a Key\n *\n * This example creates a 2048 bit RSA keypair and writes it to the current\n * directory.\n *\n *   key = OpenSSL::PKey::RSA.new 2048\n *\n *   File.write 'private_key.pem', key.private_to_pem\n *   File.write 'public_key.pem', key.public_to_pem\n *\n * === Exporting a Key\n *\n * Keys saved to disk without encryption are not secure as anyone who gets\n * ahold of the key may use it unless it is encrypted.  In order to securely\n * export a key you may export it with a password.\n *\n *   cipher = OpenSSL::Cipher.new 'aes-256-cbc'\n *   password = 'my secure password goes here'\n *\n *   key_secure = key.private_to_pem cipher, password\n *\n *   File.write 'private.secure.pem', key_secure\n *\n * OpenSSL::Cipher.ciphers returns a list of available ciphers.\n *\n * === Loading a Key\n *\n * A key can also be loaded from a file.\n *\n *   key2 = OpenSSL::PKey.read File.read 'private_key.pem'\n *   key2.public? # => true\n *   key2.private? # => true\n *\n * or\n *\n *   key3 = OpenSSL::PKey.read File.read 'public_key.pem'\n *   key3.public? # => true\n *   key3.private? # => false\n *\n * === Loading an Encrypted Key\n *\n * \\OpenSSL will prompt you for your password when loading an encrypted key.\n * If you will not be able to type in the password you may provide it when\n * loading the key:\n *\n *   key4_pem = File.read 'private.secure.pem'\n *   password = 'my secure password goes here'\n *   key4 = OpenSSL::PKey.read key4_pem, password\n *\n * == RSA Encryption\n *\n * RSA provides encryption and decryption using the public and private keys.\n * You can use a variety of padding methods depending upon the intended use of\n * encrypted data.\n *\n * === Encryption & Decryption\n *\n * Asymmetric public/private key encryption is slow and victim to attack in\n * cases where it is used without padding or directly to encrypt larger chunks\n * of data. Typical use cases for RSA encryption involve \"wrapping\" a symmetric\n * key with the public key of the recipient who would \"unwrap\" that symmetric\n * key again using their private key.\n * The following illustrates a simplified example of such a key transport\n * scheme. It shouldn't be used in practice, though, standardized protocols\n * should always be preferred.\n *\n *   wrapped_key = key.public_encrypt key\n *\n * A symmetric key encrypted with the public key can only be decrypted with\n * the corresponding private key of the recipient.\n *\n *   original_key = key.private_decrypt wrapped_key\n *\n * By default PKCS#1 padding will be used, but it is also possible to use\n * other forms of padding, see PKey::RSA for further details.\n *\n * === Signatures\n *\n * Using \"private_encrypt\" to encrypt some data with the private key is\n * equivalent to applying a digital signature to the data. A verifying\n * party may validate the signature by comparing the result of decrypting\n * the signature with \"public_decrypt\" to the original data. However,\n * OpenSSL::PKey already has methods \"sign\" and \"verify\" that handle\n * digital signatures in a standardized way - \"private_encrypt\" and\n * \"public_decrypt\" shouldn't be used in practice.\n *\n * To sign a document, a cryptographically secure hash of the document is\n * computed first, which is then signed using the private key.\n *\n *   signature = key.sign 'SHA256', document\n *\n * To validate the signature, again a hash of the document is computed and\n * the signature is decrypted using the public key. The result is then\n * compared to the hash just computed, if they are equal the signature was\n * valid.\n *\n *   if key.verify 'SHA256', signature, document\n *     puts 'Valid'\n *   else\n *     puts 'Invalid'\n *   end\n *\n * == PBKDF2 Password-based Encryption\n *\n * If supported by the underlying \\OpenSSL version used, Password-based\n * Encryption should use the features of PKCS5. If not supported or if\n * required by legacy applications, the older, less secure methods specified\n * in RFC 2898 are also supported (see below).\n *\n * PKCS5 supports PBKDF2 as it was specified in PKCS#5\n * v2.0[http://www.rsa.com/rsalabs/node.asp?id=2127]. It still uses a\n * password, a salt, and additionally a number of iterations that will\n * slow the key derivation process down. The slower this is, the more work\n * it requires being able to brute-force the resulting key.\n *\n * === Encryption\n *\n * The strategy is to first instantiate a Cipher for encryption, and\n * then to generate a random IV plus a key derived from the password\n * using PBKDF2. PKCS #5 v2.0 recommends at least 8 bytes for the salt,\n * the number of iterations largely depends on the hardware being used.\n *\n *   cipher = OpenSSL::Cipher.new 'aes-256-cbc'\n *   cipher.encrypt\n *   iv = cipher.random_iv\n *\n *   pwd = 'some hopefully not to easily guessable password'\n *   salt = OpenSSL::Random.random_bytes 16\n *   iter = 20000\n *   key_len = cipher.key_len\n *   digest = OpenSSL::Digest.new('SHA256')\n *\n *   key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)\n *   cipher.key = key\n *\n *   Now encrypt the data:\n *\n *   encrypted = cipher.update document\n *   encrypted << cipher.final\n *\n * === Decryption\n *\n * Use the same steps as before to derive the symmetric AES key, this time\n * setting the Cipher up for decryption.\n *\n *   cipher = OpenSSL::Cipher.new 'aes-256-cbc'\n *   cipher.decrypt\n *   cipher.iv = iv # the one generated with #random_iv\n *\n *   pwd = 'some hopefully not to easily guessable password'\n *   salt = ... # the one generated above\n *   iter = 20000\n *   key_len = cipher.key_len\n *   digest = OpenSSL::Digest.new('SHA256')\n *\n *   key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)\n *   cipher.key = key\n *\n *   Now decrypt the data:\n *\n *   decrypted = cipher.update encrypted\n *   decrypted << cipher.final\n *\n * == \\X509 Certificates\n *\n * === Creating a Certificate\n *\n * This example creates a self-signed certificate using an RSA key and a SHA1\n * signature.\n *\n *   key = OpenSSL::PKey::RSA.new 2048\n *   name = OpenSSL::X509::Name.parse '/CN=nobody/DC=example'\n *\n *   cert = OpenSSL::X509::Certificate.new\n *   cert.version = 2\n *   cert.serial = 0\n *   cert.not_before = Time.now\n *   cert.not_after = Time.now + 3600\n *\n *   cert.public_key = key.public_key\n *   cert.subject = name\n *\n * === Certificate Extensions\n *\n * You can add extensions to the certificate with\n * OpenSSL::SSL::ExtensionFactory to indicate the purpose of the certificate.\n *\n *   extension_factory = OpenSSL::X509::ExtensionFactory.new nil, cert\n *\n *   cert.add_extension \\\n *     extension_factory.create_extension('basicConstraints', 'CA:FALSE', true)\n *\n *   cert.add_extension \\\n *     extension_factory.create_extension(\n *       'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')\n *\n *   cert.add_extension \\\n *     extension_factory.create_extension('subjectKeyIdentifier', 'hash')\n *\n * The list of supported extensions (and in some cases their possible values)\n * can be derived from the \"objects.h\" file in the \\OpenSSL source code.\n *\n * === Signing a Certificate\n *\n * To sign a certificate set the issuer and use OpenSSL::X509::Certificate#sign\n * with a digest algorithm.  This creates a self-signed cert because we're using\n * the same name and key to sign the certificate as was used to create the\n * certificate.\n *\n *   cert.issuer = name\n *   cert.sign key, OpenSSL::Digest.new('SHA1')\n *\n *   open 'certificate.pem', 'w' do |io| io.write cert.to_pem end\n *\n * === Loading a Certificate\n *\n * Like a key, a cert can also be loaded from a file.\n *\n *   cert2 = OpenSSL::X509::Certificate.new File.read 'certificate.pem'\n *\n * === Verifying a Certificate\n *\n * Certificate#verify will return true when a certificate was signed with the\n * given public key.\n *\n *   raise 'certificate can not be verified' unless cert2.verify key\n *\n * == Certificate Authority\n *\n * A certificate authority (CA) is a trusted third party that allows you to\n * verify the ownership of unknown certificates.  The CA issues key signatures\n * that indicate it trusts the user of that key.  A user encountering the key\n * can verify the signature by using the CA's public key.\n *\n * === CA Key\n *\n * CA keys are valuable, so we encrypt and save it to disk and make sure it is\n * not readable by other users.\n *\n *   ca_key = OpenSSL::PKey::RSA.new 2048\n *   password = 'my secure password goes here'\n *\n *   cipher = 'aes-256-cbc'\n *\n *   open 'ca_key.pem', 'w', 0400 do |io|\n *     io.write ca_key.private_to_pem(cipher, password)\n *   end\n *\n * === CA Certificate\n *\n * A CA certificate is created the same way we created a certificate above, but\n * with different extensions.\n *\n *   ca_name = OpenSSL::X509::Name.parse '/CN=ca/DC=example'\n *\n *   ca_cert = OpenSSL::X509::Certificate.new\n *   ca_cert.serial = 0\n *   ca_cert.version = 2\n *   ca_cert.not_before = Time.now\n *   ca_cert.not_after = Time.now + 86400\n *\n *   ca_cert.public_key = ca_key.public_key\n *   ca_cert.subject = ca_name\n *   ca_cert.issuer = ca_name\n *\n *   extension_factory = OpenSSL::X509::ExtensionFactory.new\n *   extension_factory.subject_certificate = ca_cert\n *   extension_factory.issuer_certificate = ca_cert\n *\n *   ca_cert.add_extension \\\n *     extension_factory.create_extension('subjectKeyIdentifier', 'hash')\n *\n * This extension indicates the CA's key may be used as a CA.\n *\n *   ca_cert.add_extension \\\n *     extension_factory.create_extension('basicConstraints', 'CA:TRUE', true)\n *\n * This extension indicates the CA's key may be used to verify signatures on\n * both certificates and certificate revocations.\n *\n *   ca_cert.add_extension \\\n *     extension_factory.create_extension(\n *       'keyUsage', 'cRLSign,keyCertSign', true)\n *\n * Root CA certificates are self-signed.\n *\n *   ca_cert.sign ca_key, OpenSSL::Digest.new('SHA1')\n *\n * The CA certificate is saved to disk so it may be distributed to all the\n * users of the keys this CA will sign.\n *\n *   open 'ca_cert.pem', 'w' do |io|\n *     io.write ca_cert.to_pem\n *   end\n *\n * === Certificate Signing Request\n *\n * The CA signs keys through a Certificate Signing Request (CSR).  The CSR\n * contains the information necessary to identify the key.\n *\n *   csr = OpenSSL::X509::Request.new\n *   csr.version = 0\n *   csr.subject = name\n *   csr.public_key = key.public_key\n *   csr.sign key, OpenSSL::Digest.new('SHA1')\n *\n * A CSR is saved to disk and sent to the CA for signing.\n *\n *   open 'csr.pem', 'w' do |io|\n *     io.write csr.to_pem\n *   end\n *\n * === Creating a Certificate from a CSR\n *\n * Upon receiving a CSR the CA will verify it before signing it.  A minimal\n * verification would be to check the CSR's signature.\n *\n *   csr = OpenSSL::X509::Request.new File.read 'csr.pem'\n *\n *   raise 'CSR can not be verified' unless csr.verify csr.public_key\n *\n * After verification a certificate is created, marked for various usages,\n * signed with the CA key and returned to the requester.\n *\n *   csr_cert = OpenSSL::X509::Certificate.new\n *   csr_cert.serial = 0\n *   csr_cert.version = 2\n *   csr_cert.not_before = Time.now\n *   csr_cert.not_after = Time.now + 600\n *\n *   csr_cert.subject = csr.subject\n *   csr_cert.public_key = csr.public_key\n *   csr_cert.issuer = ca_cert.subject\n *\n *   extension_factory = OpenSSL::X509::ExtensionFactory.new\n *   extension_factory.subject_certificate = csr_cert\n *   extension_factory.issuer_certificate = ca_cert\n *\n *   csr_cert.add_extension \\\n *     extension_factory.create_extension('basicConstraints', 'CA:FALSE')\n *\n *   csr_cert.add_extension \\\n *     extension_factory.create_extension(\n *       'keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')\n *\n *   csr_cert.add_extension \\\n *     extension_factory.create_extension('subjectKeyIdentifier', 'hash')\n *\n *   csr_cert.sign ca_key, OpenSSL::Digest.new('SHA1')\n *\n *   open 'csr_cert.pem', 'w' do |io|\n *     io.write csr_cert.to_pem\n *   end\n *\n * == \\SSL and TLS Connections\n *\n * Using our created key and certificate we can create an \\SSL or TLS\n * connection. An OpenSSL::SSL::SSLContext is used to set up an \\SSL session.\n *\n *   context = OpenSSL::SSL::SSLContext.new\n *\n * === \\SSL Server\n *\n * An \\SSL server requires the certificate and private key to communicate\n * securely with its clients:\n *\n *   context.cert = cert\n *   context.key = key\n *\n * Then create an OpenSSL::SSL::SSLServer with a TCP server socket and the\n * context.  Use the SSLServer like an ordinary TCP server.\n *\n *   require 'socket'\n *\n *   tcp_server = TCPServer.new 5000\n *   ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context\n *\n *   loop do\n *     ssl_connection = ssl_server.accept\n *\n *     data = ssl_connection.gets\n *\n *     response = \"I got #{data.dump}\"\n *     puts response\n *\n *     ssl_connection.puts \"I got #{data.dump}\"\n *     ssl_connection.close\n *   end\n *\n * === \\SSL client\n *\n * An \\SSL client is created with a TCP socket and the context.\n * OpenSSL::SSL::SSLSocket#connect must be called to initiate the \\SSL handshake\n * and start encryption.  A key and certificate are not required for the client\n * socket.\n *\n * Note that OpenSSL::SSL::SSLSocket#close doesn't close the underlying socket\n * by default. Set OpenSSL::SSL::SSLSocket#sync_close to true if you want.\n *\n *   require 'socket'\n *\n *   tcp_socket = TCPSocket.new 'localhost', 5000\n *   ssl_client = OpenSSL::SSL::SSLSocket.new tcp_socket, context\n *   ssl_client.sync_close = true\n *   ssl_client.connect\n *\n *   ssl_client.puts \"hello server!\"\n *   puts ssl_client.gets\n *\n *   ssl_client.close # shutdown the TLS connection and close tcp_socket\n *\n * === Peer Verification\n *\n * An unverified \\SSL connection does not provide much security.  For enhanced\n * security the client or server can verify the certificate of its peer.\n *\n * The client can be modified to verify the server's certificate against the\n * certificate authority's certificate:\n *\n *   context.ca_file = 'ca_cert.pem'\n *   context.verify_mode = OpenSSL::SSL::VERIFY_PEER\n *\n *   require 'socket'\n *\n *   tcp_socket = TCPSocket.new 'localhost', 5000\n *   ssl_client = OpenSSL::SSL::SSLSocket.new tcp_socket, context\n *   ssl_client.connect\n *\n *   ssl_client.puts \"hello server!\"\n *   puts ssl_client.gets\n *\n * If the server certificate is invalid or <tt>context.ca_file</tt> is not set\n * when verifying peers an OpenSSL::SSL::SSLError will be raised.\n *\n */\nvoid\nInit_openssl(void)\n{\n#ifdef HAVE_RB_EXT_RACTOR_SAFE\n    rb_ext_ractor_safe(true);\n#endif\n\n#undef rb_intern\n    /*\n     * Init timezone info\n     */\n#if 0\n    tzset();\n#endif\n\n    /*\n     * Init all digests, ciphers\n     */\n    if (!OPENSSL_init_ssl(0, NULL))\n        rb_raise(rb_eRuntimeError, \"OPENSSL_init_ssl\");\n\n    /*\n     * Init main module\n     */\n    rb_global_variable(&mOSSL);\n    mOSSL = rb_define_module(\"OpenSSL\");\n    rb_define_singleton_method(mOSSL, \"fixed_length_secure_compare\", ossl_crypto_fixed_length_secure_compare, 2);\n\n    /*\n     * \\OpenSSL library version string used to compile the Ruby/OpenSSL\n     * extension. This may differ from the version used at runtime.\n     */\n    rb_define_const(mOSSL, \"OPENSSL_VERSION\",\n                    rb_obj_freeze(rb_str_new_cstr(OPENSSL_VERSION_TEXT)));\n\n    /*\n     * \\OpenSSL library version string currently used at runtime.\n     */\n    rb_define_const(\n        mOSSL,\n        \"OPENSSL_LIBRARY_VERSION\",\n        rb_obj_freeze(rb_str_new_cstr(OpenSSL_version(OPENSSL_VERSION)))\n    );\n\n    /*\n     * \\OpenSSL library version number used to compile the Ruby/OpenSSL\n     * extension. This may differ from the version used at runtime.\n     *\n     * The version number is encoded into a single integer value. The number\n     * follows the format:\n     *\n     * [\\OpenSSL 3.0.0 or later]\n     *   <tt>0xMNN00PP0</tt> (major minor 00 patch 0)\n     * [\\OpenSSL 1.1.1 or earlier]\n     *   <tt>0xMNNFFPPS</tt> (major minor fix patch status)\n     * [LibreSSL]\n     *   <tt>0x20000000</tt> (a fixed value)\n     *\n     * See also the man page OPENSSL_VERSION_NUMBER(3).\n     */\n    rb_define_const(mOSSL, \"OPENSSL_VERSION_NUMBER\", INT2NUM(OPENSSL_VERSION_NUMBER));\n\n#if defined(LIBRESSL_VERSION_NUMBER)\n    /*\n     * LibreSSL library version number used to compile the Ruby/OpenSSL\n     * extension. This may differ from the version used at runtime.\n     *\n     * This constant is only defined if the extension was compiled against\n     * LibreSSL. The number follows the format:\n     * <tt>0xMNNFF00f</tt> (major minor fix 00 status).\n     *\n     * See also the man page LIBRESSL_VERSION_NUMBER(3).\n     */\n    rb_define_const(mOSSL, \"LIBRESSL_VERSION_NUMBER\", INT2NUM(LIBRESSL_VERSION_NUMBER));\n#endif\n\n    /*\n     * Boolean indicating whether the \\OpenSSL library is FIPS-capable or not.\n     * Always <tt>true</tt> for \\OpenSSL 3.0 and later.\n     *\n     * This is obsolete and will be removed in the future.\n     * See also OpenSSL.fips_mode.\n     */\n    rb_define_const(mOSSL, \"OPENSSL_FIPS\",\n/* OpenSSL 3 is FIPS-capable even when it is installed without fips option */\n#if OSSL_OPENSSL_PREREQ(3, 0, 0)\n                    Qtrue\n#elif defined(OPENSSL_FIPS)\n                    Qtrue\n#elif defined(OPENSSL_IS_AWSLC) // AWS-LC FIPS can only be enabled during compile time.\n                    FIPS_mode() ? Qtrue : Qfalse\n#else\n                    Qfalse\n#endif\n                   );\n\n    rb_define_module_function(mOSSL, \"fips_mode\", ossl_fips_mode_get, 0);\n    rb_define_module_function(mOSSL, \"fips_mode=\", ossl_fips_mode_set, 1);\n\n    rb_global_variable(&eOSSLError);\n    /*\n     * Generic error class for OpenSSL. All error classes in this library\n     * inherit from this class.\n     *\n     * This class indicates that an error was reported by the underlying\n     * \\OpenSSL library.\n     */\n    eOSSLError = rb_define_class_under(mOSSL, \"OpenSSLError\", rb_eStandardError);\n    /*\n     * \\OpenSSL error queue entries captured at the time the exception was\n     * raised. The same information is printed to stderr if OpenSSL.debug is\n     * set to +true+.\n     *\n     * This is an array of zero or more strings, ordered from the oldest to the\n     * newest. The format of the strings is not stable and may vary across\n     * versions of \\OpenSSL or versions of this Ruby extension.\n     *\n     * See also the man page ERR_get_error(3).\n     */\n    rb_attr(eOSSLError, rb_intern_const(\"errors\"), 1, 0, 0);\n    rb_define_method(eOSSLError, \"detailed_message\", osslerror_detailed_message, -1);\n\n    /*\n     * Init debug core\n     */\n    dOSSL = Qfalse;\n    rb_global_variable(&dOSSL);\n\n    rb_define_module_function(mOSSL, \"debug\", ossl_debug_get, 0);\n    rb_define_module_function(mOSSL, \"debug=\", ossl_debug_set, 1);\n    rb_define_module_function(mOSSL, \"errors\", ossl_get_errors, 0);\n\n    /*\n     * Get ID of to_der\n     */\n    ossl_s_to_der = rb_intern(\"to_der\");\n    id_i_errors = rb_intern(\"@errors\");\n\n    /*\n     * Init components\n     */\n    Init_ossl_asn1();\n    Init_ossl_bn();\n    Init_ossl_cipher();\n    Init_ossl_config();\n    Init_ossl_digest();\n    Init_ossl_engine();\n    Init_ossl_hmac();\n    Init_ossl_kdf();\n    Init_ossl_ns_spki();\n    Init_ossl_ocsp();\n    Init_ossl_pkcs12();\n    Init_ossl_pkcs7();\n    Init_ossl_pkey();\n    Init_ossl_provider();\n    Init_ossl_rand();\n    Init_ossl_ssl();\n    Init_ossl_ts();\n    Init_ossl_x509();\n}\n"
  },
  {
    "path": "ext/openssl/ossl.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_H_)\n#define _OSSL_H_\n\n#include RUBY_EXTCONF_H\n\n#include <assert.h>\n#include <ruby.h>\n#include <errno.h>\n#include <ruby/io.h>\n#include <ruby/thread.h>\n#ifdef HAVE_RUBY_RACTOR_H\n#include <ruby/ractor.h>\n#else\n#define RUBY_TYPED_FROZEN_SHAREABLE 0\n#endif\n\n#include <openssl/opensslv.h>\n\n#include <openssl/err.h>\n#include <openssl/asn1.h>\n#include <openssl/x509v3.h>\n#include <openssl/ssl.h>\n#include <openssl/pkcs12.h>\n#include <openssl/pkcs7.h>\n#include <openssl/rand.h>\n#include <openssl/conf.h>\n#ifndef OPENSSL_NO_TS\n  #include <openssl/ts.h>\n#endif\n#include <openssl/crypto.h>\n#if !defined(OPENSSL_NO_OCSP)\n#  include <openssl/ocsp.h>\n#endif\n#include <openssl/bn.h>\n#include <openssl/rsa.h>\n#include <openssl/dsa.h>\n#include <openssl/evp.h>\n#include <openssl/dh.h>\n#include \"openssl_missing.h\"\n\n#ifndef LIBRESSL_VERSION_NUMBER\n# define OSSL_IS_LIBRESSL 0\n# define OSSL_OPENSSL_PREREQ(maj, min, pat) \\\n      (OPENSSL_VERSION_NUMBER >= ((maj << 28) | (min << 20) | (pat << 12)))\n# define OSSL_LIBRESSL_PREREQ(maj, min, pat) 0\n#else\n# define OSSL_IS_LIBRESSL 1\n# define OSSL_OPENSSL_PREREQ(maj, min, pat) 0\n# define OSSL_LIBRESSL_PREREQ(maj, min, pat) \\\n      (LIBRESSL_VERSION_NUMBER >= ((maj << 28) | (min << 20) | (pat << 12)))\n#endif\n\n#if OSSL_OPENSSL_PREREQ(3, 0, 0)\n# define OSSL_3_const const\n#else\n# define OSSL_3_const /* const */\n#endif\n\n#if !defined(OPENSSL_NO_ENGINE) && !OSSL_OPENSSL_PREREQ(3, 0, 0)\n# define OSSL_USE_ENGINE\n#endif\n\n#if OSSL_OPENSSL_PREREQ(3, 0, 0)\n# define OSSL_USE_PROVIDER\n# include <openssl/provider.h>\n#endif\n\n#if OSSL_OPENSSL_PREREQ(3, 0, 0)\n# define OSSL_HAVE_IMMUTABLE_PKEY\n#endif\n\n/*\n * Common Module\n */\nextern VALUE mOSSL;\n\n/*\n * Common Error Class\n */\nextern VALUE eOSSLError;\n\n/*\n * CheckTypes\n */\n#define OSSL_Check_Kind(obj, klass) do {\\\n    if (!rb_obj_is_kind_of((obj), (klass))) {\\\n        ossl_raise(rb_eTypeError, \"wrong argument (%\"PRIsVALUE\")! (Expected kind of %\"PRIsVALUE\")\",\\\n                   rb_obj_class(obj), (klass));\\\n    }\\\n} while (0)\n\n/*\n * Type conversions\n */\n#if !defined(NUM2UINT64T) /* in case Ruby starts to provide */\n#  if SIZEOF_LONG == 8\n#    define NUM2UINT64T(x) ((uint64_t)NUM2ULONG(x))\n#  elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8\n#    define NUM2UINT64T(x) ((uint64_t)NUM2ULL(x))\n#  else\n#    error \"unknown platform; no 64-bit width integer\"\n#  endif\n#endif\n\n/*\n * Data Conversion\n */\nSTACK_OF(X509) *ossl_x509_ary2sk(VALUE);\nSTACK_OF(X509) *ossl_protect_x509_ary2sk(VALUE,int*);\nVALUE ossl_x509_sk2ary(const STACK_OF(X509) *certs);\nVALUE ossl_x509crl_sk2ary(const STACK_OF(X509_CRL) *crl);\nVALUE ossl_x509name_sk2ary(const STACK_OF(X509_NAME) *names);\nVALUE ossl_buf2str(char *buf, int len);\nVALUE ossl_str_new(const char *, long, int *);\n#define ossl_str_adjust(str, p) \\\ndo{\\\n    long newlen = (long)((p) - (unsigned char*)RSTRING_PTR(str));\\\n    assert(newlen <= RSTRING_LEN(str));\\\n    rb_str_set_len((str), newlen);\\\n}while(0)\n/*\n * Convert binary string to hex string. The caller is responsible for\n * ensuring out has (2 * len) bytes of capacity.\n */\nvoid ossl_bin2hex(const unsigned char *in, char *out, size_t len);\n\n/*\n * Our default PEM callback\n */\n/* Convert the argument to String and validate the length. Note this may raise. */\nVALUE ossl_pem_passwd_value(VALUE);\n/* Can be casted to pem_password_cb. If a password (String) is passed as the\n * \"arbitrary data\" (typically the last parameter of PEM_{read,write}_\n * functions), uses the value. If not, but a block is given, yields to it.\n * If not either, fallbacks to PEM_def_callback() which reads from stdin. */\nint ossl_pem_passwd_cb(char *, int, int, void *);\n\n/*\n * Clear BIO* with this in PEM/DER fallback scenarios to avoid decoding\n * errors piling up in OpenSSL::Errors\n */\n#define OSSL_BIO_reset(bio) do { \\\n    (void)BIO_reset((bio)); \\\n    ossl_clear_error(); \\\n} while (0)\n\n/*\n * ERRor messages\n */\nPRINTF_ARGS(NORETURN(void ossl_raise(VALUE, const char *, ...)), 2, 3);\n/* Make exception instance from str and OpenSSL error reason string. */\nVALUE ossl_make_error(VALUE exc, VALUE str);\n/* Clear OpenSSL error queue. If dOSSL is set, rb_warn() them. */\nvoid ossl_clear_error(void);\n\n/*\n * String to DER String\n */\nVALUE ossl_to_der(VALUE);\nVALUE ossl_to_der_if_possible(VALUE);\n\n/*\n * Debug\n */\nextern VALUE dOSSL;\n\n#define OSSL_Debug(...) do { \\\n    if (dOSSL == Qtrue) { \\\n        fprintf(stderr, \"OSSL_DEBUG: \"); \\\n        fprintf(stderr, __VA_ARGS__); \\\n        fprintf(stderr, \" [%s:%d]\\n\", __FILE__, __LINE__); \\\n    } \\\n} while (0)\n\n/*\n * Include all parts\n */\n#include \"ossl_asn1.h\"\n#include \"ossl_bio.h\"\n#include \"ossl_bn.h\"\n#include \"ossl_cipher.h\"\n#include \"ossl_config.h\"\n#include \"ossl_digest.h\"\n#include \"ossl_engine.h\"\n#include \"ossl_hmac.h\"\n#include \"ossl_kdf.h\"\n#include \"ossl_ns_spki.h\"\n#include \"ossl_ocsp.h\"\n#include \"ossl_pkcs12.h\"\n#include \"ossl_pkcs7.h\"\n#include \"ossl_pkey.h\"\n#include \"ossl_provider.h\"\n#include \"ossl_rand.h\"\n#include \"ossl_ssl.h\"\n#include \"ossl_ts.h\"\n#include \"ossl_x509.h\"\n\nvoid Init_openssl(void);\n\n#endif /* _OSSL_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_asn1.c",
    "content": "/*\n * 'OpenSSL for Ruby' team members\n * Copyright (C) 2003\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n/********/\n/*\n * ASN1 module\n */\n#define ossl_asn1_get_value(o)           rb_attr_get((o),sivVALUE)\n#define ossl_asn1_get_tag(o)             rb_attr_get((o),sivTAG)\n#define ossl_asn1_get_tagging(o)         rb_attr_get((o),sivTAGGING)\n#define ossl_asn1_get_tag_class(o)       rb_attr_get((o),sivTAG_CLASS)\n#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)\n\n#define ossl_asn1_set_value(o,v)           rb_ivar_set((o),sivVALUE,(v))\n#define ossl_asn1_set_tag(o,v)             rb_ivar_set((o),sivTAG,(v))\n#define ossl_asn1_set_tagging(o,v)         rb_ivar_set((o),sivTAGGING,(v))\n#define ossl_asn1_set_tag_class(o,v)       rb_ivar_set((o),sivTAG_CLASS,(v))\n#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))\n\nVALUE mASN1;\nstatic VALUE eASN1Error;\n\nVALUE cASN1Data;\nstatic VALUE cASN1Primitive;\nstatic VALUE cASN1Constructive;\n\nstatic VALUE cASN1EndOfContent;\nstatic VALUE cASN1Boolean;                           /* BOOLEAN           */\nstatic VALUE cASN1Integer, cASN1Enumerated;          /* INTEGER           */\nstatic VALUE cASN1BitString;                         /* BIT STRING        */\nstatic VALUE cASN1OctetString, cASN1UTF8String;      /* STRINGs           */\nstatic VALUE cASN1NumericString, cASN1PrintableString;\nstatic VALUE cASN1T61String, cASN1VideotexString;\nstatic VALUE cASN1IA5String, cASN1GraphicString;\nstatic VALUE cASN1ISO64String, cASN1GeneralString;\nstatic VALUE cASN1UniversalString, cASN1BMPString;\nstatic VALUE cASN1Null;                              /* NULL              */\nstatic VALUE cASN1ObjectId;                          /* OBJECT IDENTIFIER */\nstatic VALUE cASN1UTCTime, cASN1GeneralizedTime;     /* TIME              */\nstatic VALUE cASN1Sequence, cASN1Set;                /* CONSTRUCTIVE      */\n\nstatic VALUE sym_IMPLICIT, sym_EXPLICIT;\nstatic VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;\nstatic ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;\nstatic ID id_each;\n\n/*\n * DATE conversion\n */\nstatic VALUE\ntime_utc_new(VALUE args)\n{\n    return rb_funcallv(rb_cTime, rb_intern(\"utc\"), 6, (VALUE *)args);\n}\n\nstatic VALUE\ntime_utc_new_rescue(VALUE args, VALUE exc)\n{\n    rb_raise(eASN1Error, \"invalid time\");\n}\n\nVALUE\nasn1time_to_time(const ASN1_TIME *time)\n{\n    struct tm tm;\n    if (!ASN1_TIME_to_tm(time, &tm))\n        ossl_raise(eASN1Error, \"ASN1_TIME_to_tm\");\n\n    VALUE args[] = {\n        INT2NUM(tm.tm_year + 1900),\n        INT2NUM(tm.tm_mon + 1),\n        INT2NUM(tm.tm_mday),\n        INT2NUM(tm.tm_hour),\n        INT2NUM(tm.tm_min),\n        INT2NUM(tm.tm_sec),\n    };\n    return rb_rescue2(time_utc_new, (VALUE)args, time_utc_new_rescue, Qnil,\n                      rb_eArgError, 0);\n}\n\nstatic VALUE\nasn1time_to_time_i(VALUE arg)\n{\n    return asn1time_to_time((ASN1_TIME *)arg);\n}\n\nvoid\nossl_time_split(VALUE time, time_t *sec, int *days)\n{\n    VALUE num = rb_Integer(time);\n\n    if (FIXNUM_P(num)) {\n        time_t t = FIX2LONG(num);\n        *sec = t % 86400;\n        *days = rb_long2int(t / 86400);\n    }\n    else {\n        *days = NUM2INT(rb_funcall(num, rb_intern(\"/\"), 1, INT2FIX(86400)));\n        *sec = NUM2TIMET(rb_funcall(num, rb_intern(\"%\"), 1, INT2FIX(86400)));\n    }\n}\n\n/*\n * STRING conversion\n */\nVALUE\nasn1str_to_str(const ASN1_STRING *str)\n{\n    return rb_str_new((const char *)ASN1_STRING_get0_data(str),\n                      ASN1_STRING_length(str));\n}\n\n/*\n * ASN1_INTEGER conversions\n */\nVALUE\nasn1integer_to_num(const ASN1_INTEGER *ai)\n{\n    BIGNUM *bn;\n    VALUE num;\n\n    if (!ai) {\n        ossl_raise(rb_eTypeError, \"ASN1_INTEGER is NULL!\");\n    }\n\n    num = ossl_bn_new(BN_value_one());\n    bn = GetBNPtr(num);\n\n    if (ASN1_STRING_type(ai) == V_ASN1_ENUMERATED)\n        bn = ASN1_ENUMERATED_to_BN(ai, bn);\n    else\n        bn = ASN1_INTEGER_to_BN(ai, bn);\n\n    if (!bn)\n        ossl_raise(eOSSLError, NULL);\n\n    return num;\n}\n\nASN1_INTEGER *\nnum_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)\n{\n    BIGNUM *bn;\n\n    if (NIL_P(obj))\n        ossl_raise(rb_eTypeError, \"Can't convert nil into Integer\");\n\n    bn = GetBNPtr(obj);\n\n    if (!(ai = BN_to_ASN1_INTEGER(bn, ai)))\n        ossl_raise(eOSSLError, NULL);\n\n    return ai;\n}\n\nstatic VALUE\nasn1integer_to_num_i(VALUE arg)\n{\n    return asn1integer_to_num((ASN1_INTEGER *)arg);\n}\n\n/*\n * ASN1_OBJECT conversions\n */\nVALUE\nossl_asn1obj_to_string_oid(const ASN1_OBJECT *a1obj)\n{\n    VALUE str;\n    int len;\n\n    str = rb_usascii_str_new(NULL, 127);\n    len = OBJ_obj2txt(RSTRING_PTR(str), RSTRING_LENINT(str), a1obj, 1);\n    if (len <= 0 || len == INT_MAX)\n        ossl_raise(eOSSLError, \"OBJ_obj2txt\");\n    if (len > RSTRING_LEN(str)) {\n        /* +1 is for the \\0 terminator added by OBJ_obj2txt() */\n        rb_str_resize(str, len + 1);\n        len = OBJ_obj2txt(RSTRING_PTR(str), len + 1, a1obj, 1);\n        if (len <= 0)\n            ossl_raise(eOSSLError, \"OBJ_obj2txt\");\n    }\n    rb_str_set_len(str, len);\n    return str;\n}\n\nVALUE\nossl_asn1obj_to_string(const ASN1_OBJECT *obj)\n{\n    int nid = OBJ_obj2nid(obj);\n    if (nid != NID_undef)\n        return rb_str_new_cstr(OBJ_nid2sn(nid));\n    return ossl_asn1obj_to_string_oid(obj);\n}\n\nVALUE\nossl_asn1obj_to_string_long_name(const ASN1_OBJECT *obj)\n{\n    int nid = OBJ_obj2nid(obj);\n    if (nid != NID_undef)\n        return rb_str_new_cstr(OBJ_nid2ln(nid));\n    return ossl_asn1obj_to_string_oid(obj);\n}\n\n/*\n * Ruby to ASN1 converters\n */\nstatic ASN1_BOOLEAN\nobj_to_asn1bool(VALUE obj)\n{\n    if (NIL_P(obj))\n        ossl_raise(rb_eTypeError, \"Can't convert nil into Boolean\");\n\n    return RTEST(obj) ? 0xff : 0x0;\n}\n\nstatic ASN1_INTEGER*\nobj_to_asn1int(VALUE obj)\n{\n    return num_to_asn1integer(obj, NULL);\n}\n\nstatic ASN1_BIT_STRING*\nobj_to_asn1bstr(VALUE obj, int unused_bits)\n{\n    ASN1_BIT_STRING *bstr;\n\n    if (unused_bits < 0 || unused_bits > 7)\n        ossl_raise(eASN1Error, \"unused_bits for a bitstring value must be in \"\\\n                   \"the range 0 to 7\");\n    StringValue(obj);\n    if (!(bstr = ASN1_BIT_STRING_new()))\n        ossl_raise(eASN1Error, \"ASN1_BIT_STRING_new\");\n    if (!ASN1_BIT_STRING_set1(bstr, (uint8_t *)RSTRING_PTR(obj),\n                              RSTRING_LEN(obj), unused_bits))\n        ossl_raise(eASN1Error, \"ASN1_BIT_STRING_set1\");\n\n    return bstr;\n}\n\nstatic ASN1_STRING*\nobj_to_asn1str(VALUE obj)\n{\n    ASN1_STRING *str;\n\n    StringValue(obj);\n    if(!(str = ASN1_STRING_new()))\n        ossl_raise(eASN1Error, NULL);\n    ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LENINT(obj));\n\n    return str;\n}\n\nstatic ASN1_NULL*\nobj_to_asn1null(VALUE obj)\n{\n    ASN1_NULL *null;\n\n    if(!NIL_P(obj))\n        ossl_raise(eASN1Error, \"nil expected\");\n    if(!(null = ASN1_NULL_new()))\n        ossl_raise(eASN1Error, NULL);\n\n    return null;\n}\n\nASN1_OBJECT *\nossl_to_asn1obj(VALUE obj)\n{\n    ASN1_OBJECT *a1obj;\n\n    StringValueCStr(obj);\n    a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0);\n    if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1);\n    if(!a1obj) ossl_raise(eASN1Error, \"invalid OBJECT ID %\"PRIsVALUE, obj);\n\n    return a1obj;\n}\n\nstatic ASN1_UTCTIME *\nobj_to_asn1utime(VALUE time)\n{\n    time_t sec;\n    ASN1_UTCTIME *t;\n\n    int off_days;\n\n    ossl_time_split(time, &sec, &off_days);\n    if (!(t = ASN1_UTCTIME_adj(NULL, sec, off_days, 0)))\n        ossl_raise(eASN1Error, NULL);\n\n    return t;\n}\n\nstatic ASN1_GENERALIZEDTIME *\nobj_to_asn1gtime(VALUE time)\n{\n    time_t sec;\n    ASN1_GENERALIZEDTIME *t;\n\n    int off_days;\n\n    ossl_time_split(time, &sec, &off_days);\n    if (!(t = ASN1_GENERALIZEDTIME_adj(NULL, sec, off_days, 0)))\n        ossl_raise(eASN1Error, NULL);\n\n    return t;\n}\n\nstatic ASN1_STRING*\nobj_to_asn1derstr(VALUE obj)\n{\n    ASN1_STRING *a1str;\n    VALUE str;\n\n    str = ossl_to_der(obj);\n    if(!(a1str = ASN1_STRING_new()))\n        ossl_raise(eASN1Error, NULL);\n    ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LENINT(str));\n\n    return a1str;\n}\n\n/*\n * DER to Ruby converters\n */\nstatic VALUE\ndecode_bool(unsigned char* der, long length)\n{\n    const unsigned char *p = der;\n\n    if (length != 3)\n        ossl_raise(eASN1Error, \"invalid length for BOOLEAN\");\n    if (p[0] != 1 || p[1] != 1)\n        ossl_raise(eASN1Error, \"invalid BOOLEAN\");\n\n    return p[2] ? Qtrue : Qfalse;\n}\n\nstatic VALUE\ndecode_int(unsigned char* der, long length)\n{\n    ASN1_INTEGER *ai;\n    const unsigned char *p;\n    VALUE ret;\n    int status = 0;\n\n    p = der;\n    if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length)))\n        ossl_raise(eASN1Error, NULL);\n    ret = rb_protect(asn1integer_to_num_i,\n                     (VALUE)ai, &status);\n    ASN1_INTEGER_free(ai);\n    if(status) rb_jump_tag(status);\n\n    return ret;\n}\n\nstatic VALUE\ndecode_bstr(unsigned char* der, long length, int *unused_bits)\n{\n    ASN1_BIT_STRING *bstr;\n    const unsigned char *p;\n    size_t len;\n    VALUE ret;\n    int state;\n\n    p = der;\n    if (!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))\n        ossl_raise(eASN1Error, \"d2i_ASN1_BIT_STRING\");\n    if (!ASN1_BIT_STRING_get_length(bstr, &len, unused_bits)) {\n        ASN1_BIT_STRING_free(bstr);\n        ossl_raise(eASN1Error, \"ASN1_BIT_STRING_get_length\");\n    }\n    ret = ossl_str_new((const char *)ASN1_STRING_get0_data(bstr), len, &state);\n    ASN1_BIT_STRING_free(bstr);\n    if (state)\n        rb_jump_tag(state);\n\n    return ret;\n}\n\nstatic VALUE\ndecode_enum(unsigned char* der, long length)\n{\n    ASN1_ENUMERATED *ai;\n    const unsigned char *p;\n    VALUE ret;\n    int status = 0;\n\n    p = der;\n    if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length)))\n        ossl_raise(eASN1Error, NULL);\n    ret = rb_protect(asn1integer_to_num_i,\n                     (VALUE)ai, &status);\n    ASN1_ENUMERATED_free(ai);\n    if(status) rb_jump_tag(status);\n\n    return ret;\n}\n\nstatic VALUE\ndecode_null(unsigned char* der, long length)\n{\n    ASN1_NULL *null;\n    const unsigned char *p;\n\n    p = der;\n    if(!(null = d2i_ASN1_NULL(NULL, &p, length)))\n        ossl_raise(eASN1Error, NULL);\n    ASN1_NULL_free(null);\n\n    return Qnil;\n}\n\nVALUE\nasn1obj_to_string_i(VALUE arg)\n{\n    return ossl_asn1obj_to_string((const ASN1_OBJECT *)arg);\n}\n\nstatic VALUE\ndecode_obj(unsigned char* der, long length)\n{\n    ASN1_OBJECT *obj;\n    const unsigned char *p;\n    VALUE ret;\n    int state;\n\n    p = der;\n    if (!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))\n        ossl_raise(eASN1Error, \"d2i_ASN1_OBJECT\");\n    ret = rb_protect(asn1obj_to_string_i, (VALUE)obj, &state);\n    ASN1_OBJECT_free(obj);\n    if (state)\n        rb_jump_tag(state);\n    return ret;\n}\n\nstatic VALUE\ndecode_time(unsigned char* der, long length)\n{\n    ASN1_TIME *time;\n    const unsigned char *p;\n    VALUE ret;\n    int status = 0;\n\n    p = der;\n    if(!(time = d2i_ASN1_TIME(NULL, &p, length)))\n        ossl_raise(eASN1Error, NULL);\n    ret = rb_protect(asn1time_to_time_i,\n                     (VALUE)time, &status);\n    ASN1_TIME_free(time);\n    if(status) rb_jump_tag(status);\n\n    return ret;\n}\n\nstatic VALUE\ndecode_eoc(unsigned char *der, long length)\n{\n    if (length != 2 || !(der[0] == 0x00 && der[1] == 0x00))\n        ossl_raise(eASN1Error, NULL);\n\n    return rb_str_new(\"\", 0);\n}\n\n/********/\n\ntypedef struct {\n    const char *name;\n    VALUE *klass;\n} ossl_asn1_info_t;\n\nstatic const ossl_asn1_info_t ossl_asn1_info[] = {\n    { \"EOC\",               &cASN1EndOfContent,    },  /*  0 */\n    { \"BOOLEAN\",           &cASN1Boolean,         },  /*  1 */\n    { \"INTEGER\",           &cASN1Integer,         },  /*  2 */\n    { \"BIT_STRING\",        &cASN1BitString,       },  /*  3 */\n    { \"OCTET_STRING\",      &cASN1OctetString,     },  /*  4 */\n    { \"NULL\",              &cASN1Null,            },  /*  5 */\n    { \"OBJECT\",            &cASN1ObjectId,        },  /*  6 */\n    { \"OBJECT_DESCRIPTOR\", NULL,                  },  /*  7 */\n    { \"EXTERNAL\",          NULL,                  },  /*  8 */\n    { \"REAL\",              NULL,                  },  /*  9 */\n    { \"ENUMERATED\",        &cASN1Enumerated,      },  /* 10 */\n    { \"EMBEDDED_PDV\",      NULL,                  },  /* 11 */\n    { \"UTF8STRING\",        &cASN1UTF8String,      },  /* 12 */\n    { \"RELATIVE_OID\",      NULL,                  },  /* 13 */\n    { \"[UNIVERSAL 14]\",    NULL,                  },  /* 14 */\n    { \"[UNIVERSAL 15]\",    NULL,                  },  /* 15 */\n    { \"SEQUENCE\",          &cASN1Sequence,        },  /* 16 */\n    { \"SET\",               &cASN1Set,             },  /* 17 */\n    { \"NUMERICSTRING\",     &cASN1NumericString,   },  /* 18 */\n    { \"PRINTABLESTRING\",   &cASN1PrintableString, },  /* 19 */\n    { \"T61STRING\",         &cASN1T61String,       },  /* 20 */\n    { \"VIDEOTEXSTRING\",    &cASN1VideotexString,  },  /* 21 */\n    { \"IA5STRING\",         &cASN1IA5String,       },  /* 22 */\n    { \"UTCTIME\",           &cASN1UTCTime,         },  /* 23 */\n    { \"GENERALIZEDTIME\",   &cASN1GeneralizedTime, },  /* 24 */\n    { \"GRAPHICSTRING\",     &cASN1GraphicString,   },  /* 25 */\n    { \"ISO64STRING\",       &cASN1ISO64String,     },  /* 26 */\n    { \"GENERALSTRING\",     &cASN1GeneralString,   },  /* 27 */\n    { \"UNIVERSALSTRING\",   &cASN1UniversalString, },  /* 28 */\n    { \"CHARACTER_STRING\",  NULL,                  },  /* 29 */\n    { \"BMPSTRING\",         &cASN1BMPString,       },  /* 30 */\n};\n\nenum {ossl_asn1_info_size = (sizeof(ossl_asn1_info)/sizeof(ossl_asn1_info[0]))};\n\nstatic VALUE class_tag_map;\n\nstatic int ossl_asn1_default_tag(VALUE obj);\n\nstatic ASN1_TYPE *\nossl_asn1_get_asn1type(VALUE obj)\n{\n    ASN1_TYPE *ret;\n    VALUE value, rflag;\n    void *ptr;\n    typedef void free_func_type(void *);\n    free_func_type *free_func;\n    int tag;\n\n    tag = ossl_asn1_default_tag(obj);\n    value = ossl_asn1_get_value(obj);\n    switch(tag){\n      case V_ASN1_BOOLEAN:\n        ptr = (void*)(VALUE)obj_to_asn1bool(value);\n        free_func = NULL;\n        break;\n      case V_ASN1_INTEGER:         /* FALLTHROUGH */\n      case V_ASN1_ENUMERATED:\n        ptr = obj_to_asn1int(value);\n        free_func = (free_func_type *)ASN1_INTEGER_free;\n        break;\n      case V_ASN1_BIT_STRING:\n        rflag = rb_attr_get(obj, sivUNUSED_BITS);\n        ptr = obj_to_asn1bstr(value, NUM2INT(rflag));\n        free_func = (free_func_type *)ASN1_BIT_STRING_free;\n        break;\n      case V_ASN1_NULL:\n        ptr = obj_to_asn1null(value);\n        free_func = (free_func_type *)ASN1_NULL_free;\n        break;\n      case V_ASN1_OCTET_STRING:    /* FALLTHROUGH */\n      case V_ASN1_UTF8STRING:      /* FALLTHROUGH */\n      case V_ASN1_NUMERICSTRING:   /* FALLTHROUGH */\n      case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */\n      case V_ASN1_T61STRING:       /* FALLTHROUGH */\n      case V_ASN1_VIDEOTEXSTRING:  /* FALLTHROUGH */\n      case V_ASN1_IA5STRING:       /* FALLTHROUGH */\n      case V_ASN1_GRAPHICSTRING:   /* FALLTHROUGH */\n      case V_ASN1_ISO64STRING:     /* FALLTHROUGH */\n      case V_ASN1_GENERALSTRING:   /* FALLTHROUGH */\n      case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */\n      case V_ASN1_BMPSTRING:\n        ptr = obj_to_asn1str(value);\n        free_func = (free_func_type *)ASN1_STRING_free;\n        break;\n      case V_ASN1_OBJECT:\n        ptr = ossl_to_asn1obj(value);\n        free_func = (free_func_type *)ASN1_OBJECT_free;\n        break;\n      case V_ASN1_UTCTIME:\n        ptr = obj_to_asn1utime(value);\n        free_func = (free_func_type *)ASN1_TIME_free;\n        break;\n      case V_ASN1_GENERALIZEDTIME:\n        ptr = obj_to_asn1gtime(value);\n        free_func = (free_func_type *)ASN1_TIME_free;\n        break;\n      case V_ASN1_SET:             /* FALLTHROUGH */\n      case V_ASN1_SEQUENCE:\n        ptr = obj_to_asn1derstr(obj);\n        free_func = (free_func_type *)ASN1_STRING_free;\n        break;\n      default:\n        ossl_raise(eASN1Error, \"unsupported ASN.1 type\");\n    }\n    if(!(ret = OPENSSL_malloc(sizeof(ASN1_TYPE)))){\n        if(free_func) free_func(ptr);\n        ossl_raise(eASN1Error, \"ASN1_TYPE alloc failure\");\n    }\n    memset(ret, 0, sizeof(ASN1_TYPE));\n    ASN1_TYPE_set(ret, tag, ptr);\n\n    return ret;\n}\n\nstatic int\nossl_asn1_default_tag(VALUE obj)\n{\n    VALUE tmp_class, tag;\n\n    tmp_class = CLASS_OF(obj);\n    while (!NIL_P(tmp_class)) {\n        tag = rb_hash_lookup(class_tag_map, tmp_class);\n        if (tag != Qnil)\n            return NUM2INT(tag);\n        tmp_class = rb_class_superclass(tmp_class);\n    }\n\n    return -1;\n}\n\nstatic int\nossl_asn1_tag(VALUE obj)\n{\n    VALUE tag;\n\n    tag = ossl_asn1_get_tag(obj);\n    if(NIL_P(tag))\n        ossl_raise(eASN1Error, \"tag number not specified\");\n\n    return NUM2INT(tag);\n}\n\nstatic int\nossl_asn1_tag_class(VALUE obj)\n{\n    VALUE s;\n\n    s = ossl_asn1_get_tag_class(obj);\n    if (NIL_P(s) || s == sym_UNIVERSAL)\n        return V_ASN1_UNIVERSAL;\n    else if (s == sym_APPLICATION)\n        return V_ASN1_APPLICATION;\n    else if (s == sym_CONTEXT_SPECIFIC)\n        return V_ASN1_CONTEXT_SPECIFIC;\n    else if (s == sym_PRIVATE)\n        return V_ASN1_PRIVATE;\n    else\n        ossl_raise(eASN1Error, \"invalid tag class\");\n}\n\nstatic VALUE\nossl_asn1_class2sym(int tc)\n{\n    if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)\n        return sym_PRIVATE;\n    else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)\n        return sym_CONTEXT_SPECIFIC;\n    else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)\n        return sym_APPLICATION;\n    else\n        return sym_UNIVERSAL;\n}\n\n/*\n * call-seq:\n *    OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data\n *\n * _value_: Please have a look at Constructive and Primitive to see how Ruby\n * types are mapped to ASN.1 types and vice versa.\n *\n * _tag_: An Integer indicating the tag number.\n *\n * _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for\n * possible values.\n *\n * == Example\n *   asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)\n *   tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER\n */\nstatic VALUE\nossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)\n{\n    if(!SYMBOL_P(tag_class))\n        ossl_raise(eASN1Error, \"invalid tag class\");\n    ossl_asn1_set_tag(self, tag);\n    ossl_asn1_set_value(self, value);\n    ossl_asn1_set_tag_class(self, tag_class);\n    ossl_asn1_set_indefinite_length(self, Qfalse);\n\n    return self;\n}\n\nstatic VALUE\nto_der_internal(VALUE self, int constructed, int indef_len, VALUE body)\n{\n    int encoding = constructed ? indef_len ? 2 : 1 : 0;\n    int tag_class = ossl_asn1_tag_class(self);\n    int tag_number = ossl_asn1_tag(self);\n    int default_tag_number = ossl_asn1_default_tag(self);\n    int body_length, total_length;\n    VALUE str;\n    unsigned char *p;\n\n    body_length = RSTRING_LENINT(body);\n    if (ossl_asn1_get_tagging(self) == sym_EXPLICIT) {\n        int inner_length, e_encoding = indef_len ? 2 : 1;\n\n        if (default_tag_number == -1)\n            ossl_raise(eASN1Error, \"explicit tagging of unknown tag\");\n\n        inner_length = ASN1_object_size(encoding, body_length, default_tag_number);\n        total_length = ASN1_object_size(e_encoding, inner_length, tag_number);\n        str = rb_str_new(NULL, total_length);\n        p = (unsigned char *)RSTRING_PTR(str);\n        /* Put explicit tag */\n        ASN1_put_object(&p, e_encoding, inner_length, tag_number, tag_class);\n        /* Append inner object */\n        ASN1_put_object(&p, encoding, body_length, default_tag_number, V_ASN1_UNIVERSAL);\n        memcpy(p, RSTRING_PTR(body), body_length);\n        p += body_length;\n        if (indef_len) {\n            ASN1_put_eoc(&p); /* For inner object */\n            ASN1_put_eoc(&p); /* For wrapper object */\n        }\n    }\n    else {\n        total_length = ASN1_object_size(encoding, body_length, tag_number);\n        str = rb_str_new(NULL, total_length);\n        p = (unsigned char *)RSTRING_PTR(str);\n        ASN1_put_object(&p, encoding, body_length, tag_number, tag_class);\n        memcpy(p, RSTRING_PTR(body), body_length);\n        p += body_length;\n        if (indef_len)\n            ASN1_put_eoc(&p);\n    }\n    assert(p - (unsigned char *)RSTRING_PTR(str) == total_length);\n    return str;\n}\n\nstatic VALUE ossl_asn1prim_to_der(VALUE);\nstatic VALUE ossl_asn1cons_to_der(VALUE);\n/*\n * call-seq:\n *    asn1.to_der => DER-encoded String\n *\n * Encodes this ASN1Data into a DER-encoded String value. The result is\n * DER-encoded except for the possibility of indefinite length forms.\n * Indefinite length forms are not allowed in strict DER, so strictly speaking\n * the result of such an encoding would be a BER-encoding.\n */\nstatic VALUE\nossl_asn1data_to_der(VALUE self)\n{\n    VALUE value = ossl_asn1_get_value(self);\n\n    if (rb_obj_is_kind_of(value, rb_cArray))\n        return ossl_asn1cons_to_der(self);\n    else {\n        if (RTEST(ossl_asn1_get_indefinite_length(self)))\n            ossl_raise(eASN1Error, \"indefinite length form cannot be used \" \\\n                       \"with primitive encoding\");\n        return ossl_asn1prim_to_der(self);\n    }\n}\n\nstatic VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self);\nstatic VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,\n                               int depth, int yield, long *num_read);\n\nstatic VALUE\nint_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,\n                           VALUE tc, long *num_read)\n{\n    VALUE value, asn1data;\n    unsigned char *p;\n    int flag = 0;\n\n    p = *pp;\n\n    if(tc == sym_UNIVERSAL && tag < ossl_asn1_info_size) {\n        switch(tag){\n          case V_ASN1_EOC:\n            value = decode_eoc(p, hlen+length);\n            break;\n          case V_ASN1_BOOLEAN:\n            value = decode_bool(p, hlen+length);\n            break;\n          case V_ASN1_INTEGER:\n            value = decode_int(p, hlen+length);\n            break;\n          case V_ASN1_BIT_STRING:\n            value = decode_bstr(p, hlen+length, &flag);\n            break;\n          case V_ASN1_NULL:\n            value = decode_null(p, hlen+length);\n            break;\n          case V_ASN1_ENUMERATED:\n            value = decode_enum(p, hlen+length);\n            break;\n          case V_ASN1_OBJECT:\n            value = decode_obj(p, hlen+length);\n            break;\n          case V_ASN1_UTCTIME:           /* FALLTHROUGH */\n          case V_ASN1_GENERALIZEDTIME:\n            value = decode_time(p, hlen+length);\n            break;\n          default:\n            /* use original value */\n            p += hlen;\n            value = rb_str_new((const char *)p, length);\n            break;\n        }\n    }\n    else {\n        p += hlen;\n        value = rb_str_new((const char *)p, length);\n    }\n\n    *pp += hlen + length;\n    *num_read = hlen + length;\n\n    if (tc == sym_UNIVERSAL &&\n        tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {\n        VALUE klass = *ossl_asn1_info[tag].klass;\n        VALUE args[4];\n        args[0] = value;\n        args[1] = INT2NUM(tag);\n        args[2] = Qnil;\n        args[3] = tc;\n        asn1data = rb_obj_alloc(klass);\n        ossl_asn1_initialize(4, args, asn1data);\n        if(tag == V_ASN1_BIT_STRING){\n            rb_ivar_set(asn1data, sivUNUSED_BITS, INT2NUM(flag));\n        }\n    }\n    else {\n        asn1data = rb_obj_alloc(cASN1Data);\n        ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc);\n    }\n\n    return asn1data;\n}\n\nstatic VALUE\nint_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,\n                           long *offset, int depth, int yield, int j,\n                           int tag, VALUE tc, long *num_read)\n{\n    VALUE value, asn1data, ary;\n    int indefinite;\n    long available_len, off = *offset;\n\n    indefinite = (j == 0x21);\n    ary = rb_ary_new();\n\n    available_len = indefinite ? max_len : length;\n    while (available_len > 0) {\n        long inner_read = 0;\n        value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read);\n        *num_read += inner_read;\n        available_len -= inner_read;\n\n        if (indefinite) {\n            if (ossl_asn1_tag(value) == V_ASN1_EOC &&\n                ossl_asn1_get_tag_class(value) == sym_UNIVERSAL)\n                break;\n            if (available_len == 0)\n                ossl_raise(eASN1Error, \"EOC missing in indefinite length encoding\");\n        }\n        rb_ary_push(ary, value);\n    }\n\n    if (tc == sym_UNIVERSAL) {\n        VALUE args[4];\n        if (tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET)\n            asn1data = rb_obj_alloc(*ossl_asn1_info[tag].klass);\n        else\n            asn1data = rb_obj_alloc(cASN1Constructive);\n        args[0] = ary;\n        args[1] = INT2NUM(tag);\n        args[2] = Qnil;\n        args[3] = tc;\n        ossl_asn1_initialize(4, args, asn1data);\n    }\n    else {\n        asn1data = rb_obj_alloc(cASN1Data);\n        ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc);\n    }\n\n    if (indefinite)\n        ossl_asn1_set_indefinite_length(asn1data, Qtrue);\n    else\n        ossl_asn1_set_indefinite_length(asn1data, Qfalse);\n\n    *offset = off;\n    return asn1data;\n}\n\nstatic VALUE\nossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,\n                  int yield, long *num_read)\n{\n    unsigned char *start, *p;\n    const unsigned char *p0;\n    long len = 0, inner_read = 0, off = *offset, hlen;\n    int tag, tc, j;\n    VALUE asn1data, tag_class;\n\n    p = *pp;\n    start = p;\n    p0 = p;\n    j = ASN1_get_object(&p0, &len, &tag, &tc, length);\n    p = (unsigned char *)p0;\n    if(j & 0x80) ossl_raise(eASN1Error, NULL);\n    if(len > length) ossl_raise(eASN1Error, \"value is too short\");\n    if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)\n        tag_class = sym_PRIVATE;\n    else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)\n        tag_class = sym_CONTEXT_SPECIFIC;\n    else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)\n        tag_class = sym_APPLICATION;\n    else\n        tag_class = sym_UNIVERSAL;\n\n    hlen = p - start;\n\n    if(yield) {\n        VALUE arg = rb_ary_new();\n        rb_ary_push(arg, LONG2NUM(depth));\n        rb_ary_push(arg, LONG2NUM(*offset));\n        rb_ary_push(arg, LONG2NUM(hlen));\n        rb_ary_push(arg, LONG2NUM(len));\n        rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);\n        rb_ary_push(arg, ossl_asn1_class2sym(tc));\n        rb_ary_push(arg, INT2NUM(tag));\n        rb_yield(arg);\n    }\n\n    if(j & V_ASN1_CONSTRUCTED) {\n        *pp += hlen;\n        off += hlen;\n        asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read);\n        inner_read += hlen;\n    }\n    else {\n        if ((j & 0x01) && (len == 0))\n            ossl_raise(eASN1Error, \"indefinite length for primitive value\");\n        asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read);\n        off += hlen + len;\n    }\n    if (num_read)\n        *num_read = inner_read;\n    if (len != 0 && inner_read != hlen + len) {\n        ossl_raise(eASN1Error,\n                   \"Type mismatch. Bytes read: %ld Bytes available: %ld\",\n                   inner_read, hlen + len);\n    }\n\n    *offset = off;\n    return asn1data;\n}\n\nstatic void\nint_ossl_decode_sanity_check(long len, long read, long offset)\n{\n    if (len != 0 && (read != len || offset != len)) {\n        ossl_raise(eASN1Error,\n                   \"Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld\",\n                   read, len, offset);\n    }\n}\n\n/*\n * call-seq:\n *    OpenSSL::ASN1.traverse(asn1) -> nil\n *\n * If a block is given, it prints out each of the elements encountered.\n * Block parameters are (in that order):\n * * depth: The recursion depth, plus one with each constructed value being encountered (Integer)\n * * offset: Current byte offset (Integer)\n * * header length: Combined length in bytes of the Tag and Length headers. (Integer)\n * * length: The overall remaining length of the entire data (Integer)\n * * constructed: Whether this value is constructed or not (Boolean)\n * * tag_class: Current tag class (Symbol)\n * * tag: The current tag number (Integer)\n *\n * == Example\n *   der = File.binread('asn1data.der')\n *   OpenSSL::ASN1.traverse(der) do | depth, offset, header_len, length, constructed, tag_class, tag|\n *     puts \"Depth: #{depth} Offset: #{offset} Length: #{length}\"\n *     puts \"Header length: #{header_len} Tag: #{tag} Tag class: #{tag_class} Constructed: #{constructed}\"\n *   end\n */\nstatic VALUE\nossl_asn1_traverse(VALUE self, VALUE obj)\n{\n    unsigned char *p;\n    VALUE tmp;\n    long len, read = 0, offset = 0;\n\n    obj = ossl_to_der_if_possible(obj);\n    tmp = rb_str_new4(StringValue(obj));\n    p = (unsigned char *)RSTRING_PTR(tmp);\n    len = RSTRING_LEN(tmp);\n    ossl_asn1_decode0(&p, len, &offset, 0, 1, &read);\n    RB_GC_GUARD(tmp);\n    int_ossl_decode_sanity_check(len, read, offset);\n    return Qnil;\n}\n\n/*\n * call-seq:\n *    OpenSSL::ASN1.decode(der) -> ASN1Data\n *\n * Decodes a BER- or DER-encoded value and creates an ASN1Data instance. _der_\n * may be a String or any object that features a +.to_der+ method transforming\n * it into a BER-/DER-encoded String+\n *\n * == Example\n *   der = File.binread('asn1data')\n *   asn1 = OpenSSL::ASN1.decode(der)\n */\nstatic VALUE\nossl_asn1_decode(VALUE self, VALUE obj)\n{\n    VALUE ret;\n    unsigned char *p;\n    VALUE tmp;\n    long len, read = 0, offset = 0;\n\n    obj = ossl_to_der_if_possible(obj);\n    tmp = rb_str_new4(StringValue(obj));\n    p = (unsigned char *)RSTRING_PTR(tmp);\n    len = RSTRING_LEN(tmp);\n    ret = ossl_asn1_decode0(&p, len, &offset, 0, 0, &read);\n    RB_GC_GUARD(tmp);\n    int_ossl_decode_sanity_check(len, read, offset);\n    return ret;\n}\n\n/*\n * call-seq:\n *    OpenSSL::ASN1.decode_all(der) -> Array of ASN1Data\n *\n * Similar to #decode with the difference that #decode expects one\n * distinct value represented in _der_. #decode_all on the contrary\n * decodes a sequence of sequential BER/DER values lined up in _der_\n * and returns them as an array.\n *\n * == Example\n *   ders = File.binread('asn1data_seq')\n *   asn1_ary = OpenSSL::ASN1.decode_all(ders)\n */\nstatic VALUE\nossl_asn1_decode_all(VALUE self, VALUE obj)\n{\n    VALUE ary, val;\n    unsigned char *p;\n    long len, tmp_len = 0, read = 0, offset = 0;\n    VALUE tmp;\n\n    obj = ossl_to_der_if_possible(obj);\n    tmp = rb_str_new4(StringValue(obj));\n    p = (unsigned char *)RSTRING_PTR(tmp);\n    len = RSTRING_LEN(tmp);\n    tmp_len = len;\n    ary = rb_ary_new();\n    while (tmp_len > 0) {\n        long tmp_read = 0;\n        val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);\n        rb_ary_push(ary, val);\n        read += tmp_read;\n        tmp_len -= tmp_read;\n    }\n    RB_GC_GUARD(tmp);\n    int_ossl_decode_sanity_check(len, read, offset);\n    return ary;\n}\n\n/*\n * call-seq:\n *    OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive\n *\n * _value_: is mandatory.\n *\n * _tag_: optional, may be specified for tagged values. If no _tag_ is\n * specified, the UNIVERSAL tag corresponding to the Primitive sub-class\n * is used by default.\n *\n * _tagging_: may be used as an encoding hint to encode a value either\n * explicitly or implicitly, see ASN1 for possible values.\n *\n * _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to\n * +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then\n * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please\n * cf. ASN1.\n *\n * == Example\n *   int = OpenSSL::ASN1::Integer.new(42)\n *   zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)\n *   private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)\n */\nstatic VALUE\nossl_asn1_initialize(int argc, VALUE *argv, VALUE self)\n{\n    VALUE value, tag, tagging, tag_class;\n    int default_tag;\n\n    rb_scan_args(argc, argv, \"13\", &value, &tag, &tagging, &tag_class);\n    default_tag = ossl_asn1_default_tag(self);\n\n    if (default_tag == -1 || argc > 1) {\n        if(NIL_P(tag))\n            ossl_raise(eASN1Error, \"must specify tag number\");\n        if(!NIL_P(tagging) && !SYMBOL_P(tagging))\n            ossl_raise(eASN1Error, \"invalid tagging method\");\n        if(NIL_P(tag_class)) {\n            if (NIL_P(tagging))\n                tag_class = sym_UNIVERSAL;\n            else\n                tag_class = sym_CONTEXT_SPECIFIC;\n        }\n        if(!SYMBOL_P(tag_class))\n            ossl_raise(eASN1Error, \"invalid tag class\");\n    }\n    else{\n        tag = INT2NUM(default_tag);\n        tagging = Qnil;\n        tag_class = sym_UNIVERSAL;\n    }\n    ossl_asn1_set_tag(self, tag);\n    ossl_asn1_set_value(self, value);\n    ossl_asn1_set_tagging(self, tagging);\n    ossl_asn1_set_tag_class(self, tag_class);\n    ossl_asn1_set_indefinite_length(self, Qfalse);\n    if (default_tag == V_ASN1_BIT_STRING)\n        rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0));\n\n    return self;\n}\n\nstatic VALUE\nossl_asn1eoc_initialize(VALUE self) {\n    VALUE tag, tagging, tag_class, value;\n    tag = INT2FIX(0);\n    tagging = Qnil;\n    tag_class = sym_UNIVERSAL;\n    value = rb_str_new(\"\", 0);\n    ossl_asn1_set_tag(self, tag);\n    ossl_asn1_set_value(self, value);\n    ossl_asn1_set_tagging(self, tagging);\n    ossl_asn1_set_tag_class(self, tag_class);\n    ossl_asn1_set_indefinite_length(self, Qfalse);\n    return self;\n}\n\nstatic VALUE\nossl_asn1eoc_to_der(VALUE self)\n{\n    return rb_str_new(\"\\0\\0\", 2);\n}\n\n/*\n * call-seq:\n *    asn1.to_der => DER-encoded String\n *\n * See ASN1Data#to_der for details.\n */\nstatic VALUE\nossl_asn1prim_to_der(VALUE self)\n{\n    ASN1_TYPE *asn1;\n    long alllen, bodylen;\n    unsigned char *p0, *p1;\n    int j, tag, tc, state;\n    VALUE str;\n\n    if (ossl_asn1_default_tag(self) == -1) {\n        str = ossl_asn1_get_value(self);\n        return to_der_internal(self, 0, 0, StringValue(str));\n    }\n\n    asn1 = ossl_asn1_get_asn1type(self);\n    alllen = i2d_ASN1_TYPE(asn1, NULL);\n    if (alllen < 0) {\n        ASN1_TYPE_free(asn1);\n        ossl_raise(eASN1Error, \"i2d_ASN1_TYPE\");\n    }\n    str = ossl_str_new(NULL, alllen, &state);\n    if (state) {\n        ASN1_TYPE_free(asn1);\n        rb_jump_tag(state);\n    }\n    p0 = p1 = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_ASN1_TYPE(asn1, &p0) < 0) {\n        ASN1_TYPE_free(asn1);\n        ossl_raise(eASN1Error, \"i2d_ASN1_TYPE\");\n    }\n    ASN1_TYPE_free(asn1);\n    ossl_str_adjust(str, p0);\n\n    /* Strip header since to_der_internal() wants only the payload */\n    j = ASN1_get_object((const unsigned char **)&p1, &bodylen, &tag, &tc, alllen);\n    if (j & 0x80)\n        ossl_raise(eASN1Error, \"ASN1_get_object\"); /* should not happen */\n\n    return to_der_internal(self, 0, 0, rb_str_drop_bytes(str, alllen - bodylen));\n}\n\n/*\n * call-seq:\n *    asn1.to_der => DER-encoded String\n *\n * See ASN1Data#to_der for details.\n */\nstatic VALUE\nossl_asn1cons_to_der(VALUE self)\n{\n    VALUE ary, str;\n    long i;\n    int indef_len;\n\n    indef_len = RTEST(ossl_asn1_get_indefinite_length(self));\n    ary = rb_convert_type(ossl_asn1_get_value(self), T_ARRAY, \"Array\", \"to_a\");\n    str = rb_str_new(NULL, 0);\n    for (i = 0; i < RARRAY_LEN(ary); i++) {\n        VALUE item = RARRAY_AREF(ary, i);\n\n        if (indef_len && rb_obj_is_kind_of(item, cASN1EndOfContent)) {\n            if (i != RARRAY_LEN(ary) - 1)\n                ossl_raise(eASN1Error, \"illegal EOC octets in value\");\n\n            /*\n             * EOC is not really part of the content, but we required to add one\n             * at the end in the past.\n             */\n            break;\n        }\n\n        item = ossl_to_der_if_possible(item);\n        StringValue(item);\n        rb_str_append(str, item);\n    }\n\n    return to_der_internal(self, 1, indef_len, str);\n}\n\n/*\n * call-seq:\n *    asn1_ary.each { |asn1| block } => asn1_ary\n *\n * Calls the given block once for each element in self, passing that element\n * as parameter _asn1_. If no block is given, an enumerator is returned\n * instead.\n *\n * == Example\n *   asn1_ary.each do |asn1|\n *     puts asn1\n *   end\n */\nstatic VALUE\nossl_asn1cons_each(VALUE self)\n{\n    rb_block_call(ossl_asn1_get_value(self), id_each, 0, 0, 0, 0);\n\n    return self;\n}\n\n/*\n * call-seq:\n *    OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name)\n *\n * This adds a new ObjectId to the internal tables. Where _object_id_ is the\n * numerical form, _short_name_ is the short name, and _long_name_ is the long\n * name.\n *\n * Returns +true+ if successful. Raises an OpenSSL::ASN1::ASN1Error if it fails.\n *\n */\nstatic VALUE\nossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln)\n{\n    StringValueCStr(oid);\n    StringValueCStr(sn);\n    StringValueCStr(ln);\n\n    if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln)))\n        ossl_raise(eASN1Error, NULL);\n\n    return Qtrue;\n}\n\n/*\n * call-seq:\n *    oid.sn -> string\n *    oid.short_name -> string\n *\n * The short name of the ObjectId, as defined in <openssl/objects.h>.\n */\nstatic VALUE\nossl_asn1obj_get_sn(VALUE self)\n{\n    VALUE val, ret = Qnil;\n    int nid;\n\n    val = ossl_asn1_get_value(self);\n    if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef)\n        ret = rb_str_new2(OBJ_nid2sn(nid));\n\n    return ret;\n}\n\n/*\n * call-seq:\n *    oid.ln -> string\n *    oid.long_name -> string\n *\n * The long name of the ObjectId, as defined in <openssl/objects.h>.\n */\nstatic VALUE\nossl_asn1obj_get_ln(VALUE self)\n{\n    VALUE val, ret = Qnil;\n    int nid;\n\n    val = ossl_asn1_get_value(self);\n    if ((nid = OBJ_txt2nid(StringValueCStr(val))) != NID_undef)\n        ret = rb_str_new2(OBJ_nid2ln(nid));\n\n    return ret;\n}\n\nstatic VALUE\nasn1obj_get_oid_i(VALUE vobj)\n{\n    return ossl_asn1obj_to_string_oid((const ASN1_OBJECT *)vobj);\n}\n\n/*\n * call-seq:\n *    oid.oid -> string\n *\n * Returns a String representing the Object Identifier in the dot notation,\n * e.g. \"1.2.3.4.5\"\n */\nstatic VALUE\nossl_asn1obj_get_oid(VALUE self)\n{\n    VALUE str;\n    ASN1_OBJECT *a1obj;\n    int state;\n\n    a1obj = ossl_to_asn1obj(ossl_asn1_get_value(self));\n    str = rb_protect(asn1obj_get_oid_i, (VALUE)a1obj, &state);\n    ASN1_OBJECT_free(a1obj);\n    if (state)\n        rb_jump_tag(state);\n    return str;\n}\n\n/*\n *  call-seq:\n *     oid == other_oid => true or false\n *\n *  Returns +true+ if _other_oid_ is the same as _oid_.\n */\nstatic VALUE\nossl_asn1obj_eq(VALUE self, VALUE other)\n{\n    VALUE oid1, oid2;\n\n    if (!rb_obj_is_kind_of(other, cASN1ObjectId))\n        return Qfalse;\n\n    oid1 = ossl_asn1obj_get_oid(self);\n    oid2 = ossl_asn1obj_get_oid(other);\n    return rb_str_equal(oid1, oid2);\n}\n\n#define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \\\nstatic VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\\\n{ return rb_funcall3(cASN1##klass, rb_intern(\"new\"), argc, argv); }\n\nOSSL_ASN1_IMPL_FACTORY_METHOD(Boolean)\nOSSL_ASN1_IMPL_FACTORY_METHOD(Integer)\nOSSL_ASN1_IMPL_FACTORY_METHOD(Enumerated)\nOSSL_ASN1_IMPL_FACTORY_METHOD(BitString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(OctetString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(UTF8String)\nOSSL_ASN1_IMPL_FACTORY_METHOD(NumericString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(PrintableString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(T61String)\nOSSL_ASN1_IMPL_FACTORY_METHOD(VideotexString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(IA5String)\nOSSL_ASN1_IMPL_FACTORY_METHOD(GraphicString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(ISO64String)\nOSSL_ASN1_IMPL_FACTORY_METHOD(GeneralString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(UniversalString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(BMPString)\nOSSL_ASN1_IMPL_FACTORY_METHOD(Null)\nOSSL_ASN1_IMPL_FACTORY_METHOD(ObjectId)\nOSSL_ASN1_IMPL_FACTORY_METHOD(UTCTime)\nOSSL_ASN1_IMPL_FACTORY_METHOD(GeneralizedTime)\nOSSL_ASN1_IMPL_FACTORY_METHOD(Sequence)\nOSSL_ASN1_IMPL_FACTORY_METHOD(Set)\nOSSL_ASN1_IMPL_FACTORY_METHOD(EndOfContent)\n\nvoid\nInit_ossl_asn1(void)\n{\n#undef rb_intern\n\n    sym_UNIVERSAL = ID2SYM(rb_intern_const(\"UNIVERSAL\"));\n    sym_CONTEXT_SPECIFIC = ID2SYM(rb_intern_const(\"CONTEXT_SPECIFIC\"));\n    sym_APPLICATION = ID2SYM(rb_intern_const(\"APPLICATION\"));\n    sym_PRIVATE = ID2SYM(rb_intern_const(\"PRIVATE\"));\n    sym_EXPLICIT = ID2SYM(rb_intern_const(\"EXPLICIT\"));\n    sym_IMPLICIT = ID2SYM(rb_intern_const(\"IMPLICIT\"));\n\n    sivVALUE = rb_intern(\"@value\");\n    sivTAG = rb_intern(\"@tag\");\n    sivTAGGING = rb_intern(\"@tagging\");\n    sivTAG_CLASS = rb_intern(\"@tag_class\");\n    sivINDEFINITE_LENGTH = rb_intern(\"@indefinite_length\");\n    sivUNUSED_BITS = rb_intern(\"@unused_bits\");\n\n    /*\n     * Document-module: OpenSSL::ASN1\n     *\n     * Abstract Syntax Notation One (or ASN.1) is a notation syntax to\n     * describe data structures and is defined in ITU-T X.680. ASN.1 itself\n     * does not mandate any encoding or parsing rules, but usually ASN.1 data\n     * structures are encoded using the Distinguished Encoding Rules (DER) or\n     * less often the Basic Encoding Rules (BER) described in ITU-T X.690. DER\n     * and BER encodings are binary Tag-Length-Value (TLV) encodings that are\n     * quite concise compared to other popular data description formats such\n     * as XML, JSON etc.\n     * ASN.1 data structures are very common in cryptographic applications,\n     * e.g. X.509 public key certificates or certificate revocation lists\n     * (CRLs) are all defined in ASN.1 and DER-encoded. ASN.1, DER and BER are\n     * the building blocks of applied cryptography.\n     * The ASN1 module provides the necessary classes that allow generation\n     * of ASN.1 data structures and the methods to encode them using a DER\n     * encoding. The decode method allows parsing arbitrary BER-/DER-encoded\n     * data to a Ruby object that can then be modified and re-encoded at will.\n     *\n     * == ASN.1 class hierarchy\n     *\n     * The base class representing ASN.1 structures is ASN1Data. ASN1Data offers\n     * attributes to read and set the _tag_, the _tag_class_ and finally the\n     * _value_ of a particular ASN.1 item. Upon parsing, any tagged values\n     * (implicit or explicit) will be represented by ASN1Data instances because\n     * their \"real type\" can only be determined using out-of-band information\n     * from the ASN.1 type declaration. Since this information is normally\n     * known when encoding a type, all sub-classes of ASN1Data offer an\n     * additional attribute _tagging_ that allows to encode a value implicitly\n     * (+:IMPLICIT+) or explicitly (+:EXPLICIT+).\n     *\n     * === Constructive\n     *\n     * Constructive is, as its name implies, the base class for all\n     * constructed encodings, i.e. those that consist of several values,\n     * opposed to \"primitive\" encodings with just one single value. The value of\n     * an Constructive is always an Array.\n     *\n     * ==== ASN1::Set and ASN1::Sequence\n     *\n     * The most common constructive encodings are SETs and SEQUENCEs, which is\n     * why there are two sub-classes of Constructive representing each of\n     * them.\n     *\n     * === Primitive\n     *\n     * This is the super class of all primitive values. Primitive\n     * itself is not used when parsing ASN.1 data, all values are either\n     * instances of a corresponding sub-class of Primitive or they are\n     * instances of ASN1Data if the value was tagged implicitly or explicitly.\n     * Please cf. Primitive documentation for details on sub-classes and\n     * their respective mappings of ASN.1 data types to Ruby objects.\n     *\n     * == Possible values for _tagging_\n     *\n     * When constructing an ASN1Data object the ASN.1 type definition may\n     * require certain elements to be either implicitly or explicitly tagged.\n     * This can be achieved by setting the _tagging_ attribute manually for\n     * sub-classes of ASN1Data. Use the symbol +:IMPLICIT+ for implicit\n     * tagging and +:EXPLICIT+ if the element requires explicit tagging.\n     *\n     * == Possible values for _tag_class_\n     *\n     * It is possible to create arbitrary ASN1Data objects that also support\n     * a PRIVATE or APPLICATION tag class. Possible values for the _tag_class_\n     * attribute are:\n     * * +:UNIVERSAL+ (the default for untagged values)\n     * * +:CONTEXT_SPECIFIC+ (the default for tagged values)\n     * * +:APPLICATION+\n     * * +:PRIVATE+\n     *\n     * == Tag constants\n     *\n     * There is a constant defined for each universal tag:\n     * * OpenSSL::ASN1::EOC (0)\n     * * OpenSSL::ASN1::BOOLEAN (1)\n     * * OpenSSL::ASN1::INTEGER (2)\n     * * OpenSSL::ASN1::BIT_STRING (3)\n     * * OpenSSL::ASN1::OCTET_STRING (4)\n     * * OpenSSL::ASN1::NULL (5)\n     * * OpenSSL::ASN1::OBJECT (6)\n     * * OpenSSL::ASN1::ENUMERATED (10)\n     * * OpenSSL::ASN1::UTF8STRING (12)\n     * * OpenSSL::ASN1::SEQUENCE (16)\n     * * OpenSSL::ASN1::SET (17)\n     * * OpenSSL::ASN1::NUMERICSTRING (18)\n     * * OpenSSL::ASN1::PRINTABLESTRING (19)\n     * * OpenSSL::ASN1::T61STRING (20)\n     * * OpenSSL::ASN1::VIDEOTEXSTRING (21)\n     * * OpenSSL::ASN1::IA5STRING (22)\n     * * OpenSSL::ASN1::UTCTIME (23)\n     * * OpenSSL::ASN1::GENERALIZEDTIME (24)\n     * * OpenSSL::ASN1::GRAPHICSTRING (25)\n     * * OpenSSL::ASN1::ISO64STRING (26)\n     * * OpenSSL::ASN1::GENERALSTRING (27)\n     * * OpenSSL::ASN1::UNIVERSALSTRING (28)\n     * * OpenSSL::ASN1::BMPSTRING (30)\n     *\n     * == UNIVERSAL_TAG_NAME constant\n     *\n     * An Array that stores the name of a given tag number. These names are\n     * the same as the name of the tag constant that is additionally defined,\n     * e.g. <tt>UNIVERSAL_TAG_NAME[2] = \"INTEGER\"</tt> and <tt>OpenSSL::ASN1::INTEGER = 2</tt>.\n     *\n     * == Example usage\n     *\n     * === Decoding and viewing a DER-encoded file\n     *   require 'openssl'\n     *   require 'pp'\n     *   der = File.binread('data.der')\n     *   asn1 = OpenSSL::ASN1.decode(der)\n     *   pp der\n     *\n     * === Creating an ASN.1 structure and DER-encoding it\n     *   require 'openssl'\n     *   version = OpenSSL::ASN1::Integer.new(1)\n     *   # Explicitly 0-tagged implies context-specific tag class\n     *   serial = OpenSSL::ASN1::Integer.new(12345, 0, :EXPLICIT, :CONTEXT_SPECIFIC)\n     *   name = OpenSSL::ASN1::PrintableString.new('Data 1')\n     *   sequence = OpenSSL::ASN1::Sequence.new( [ version, serial, name ] )\n     *   der = sequence.to_der\n     */\n    mASN1 = rb_define_module_under(mOSSL, \"ASN1\");\n\n    /* Document-class: OpenSSL::ASN1::ASN1Error\n     *\n     * Generic error class for all errors raised in ASN1 and any of the\n     * classes defined in it.\n     */\n    eASN1Error = rb_define_class_under(mASN1, \"ASN1Error\", eOSSLError);\n    rb_define_module_function(mASN1, \"traverse\", ossl_asn1_traverse, 1);\n    rb_define_module_function(mASN1, \"decode\", ossl_asn1_decode, 1);\n    rb_define_module_function(mASN1, \"decode_all\", ossl_asn1_decode_all, 1);\n\n    VALUE ary = rb_ary_new_capa(ossl_asn1_info_size);\n    for (int i = 0; i < ossl_asn1_info_size; i++) {\n        const char *name = ossl_asn1_info[i].name;\n        if (name[0] == '[')\n            continue;\n        rb_define_const(mASN1, name, INT2NUM(i));\n        rb_ary_store(ary, i, rb_obj_freeze(rb_str_new_cstr(name)));\n    }\n    rb_obj_freeze(ary);\n    /*\n     * Array storing tag names at the tag's index.\n     */\n    rb_define_const(mASN1, \"UNIVERSAL_TAG_NAME\", ary);\n\n    /* Document-class: OpenSSL::ASN1::ASN1Data\n     *\n     * The top-level class representing any ASN.1 object. When parsed by\n     * ASN1.decode, tagged values are always represented by an instance\n     * of ASN1Data.\n     *\n     * == The role of ASN1Data for parsing tagged values\n     *\n     * When encoding an ASN.1 type it is inherently clear what original\n     * type (e.g. INTEGER, OCTET STRING etc.) this value has, regardless\n     * of its tagging.\n     * But opposed to the time an ASN.1 type is to be encoded, when parsing\n     * them it is not possible to deduce the \"real type\" of tagged\n     * values. This is why tagged values are generally parsed into ASN1Data\n     * instances, but with a different outcome for implicit and explicit\n     * tagging.\n     *\n     * === Example of a parsed implicitly tagged value\n     *\n     * An implicitly 1-tagged INTEGER value will be parsed as an\n     * ASN1Data with\n     * * _tag_ equal to 1\n     * * _tag_class_ equal to +:CONTEXT_SPECIFIC+\n     * * _value_ equal to a String that carries the raw encoding\n     *   of the INTEGER.\n     * This implies that a subsequent decoding step is required to\n     * completely decode implicitly tagged values.\n     *\n     * === Example of a parsed explicitly tagged value\n     *\n     * An explicitly 1-tagged INTEGER value will be parsed as an\n     * ASN1Data with\n     * * _tag_ equal to 1\n     * * _tag_class_ equal to +:CONTEXT_SPECIFIC+\n     * * _value_ equal to an Array with one single element, an\n     *   instance of OpenSSL::ASN1::Integer, i.e. the inner element\n     *   is the non-tagged primitive value, and the tagging is represented\n     *   in the outer ASN1Data\n     *\n     * == Example - Decoding an implicitly tagged INTEGER\n     *   int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) # implicit 0-tagged\n     *   seq = OpenSSL::ASN1::Sequence.new( [int] )\n     *   der = seq.to_der\n     *   asn1 = OpenSSL::ASN1.decode(der)\n     *   # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0\n     *   #              @indefinite_length=false,\n     *   #              @tag=16,\n     *   #              @tag_class=:UNIVERSAL,\n     *   #              @tagging=nil,\n     *   #              @value=\n     *   #                [#<OpenSSL::ASN1::ASN1Data:0x87326f4\n     *   #                   @indefinite_length=false,\n     *   #                   @tag=0,\n     *   #                   @tag_class=:CONTEXT_SPECIFIC,\n     *   #                   @value=\"\\x01\">]>\n     *   raw_int = asn1.value[0]\n     *   # manually rewrite tag and tag class to make it an UNIVERSAL value\n     *   raw_int.tag = OpenSSL::ASN1::INTEGER\n     *   raw_int.tag_class = :UNIVERSAL\n     *   int2 = OpenSSL::ASN1.decode(raw_int)\n     *   puts int2.value # => 1\n     *\n     * == Example - Decoding an explicitly tagged INTEGER\n     *   int = OpenSSL::ASN1::Integer.new(1, 0, :EXPLICIT) # explicit 0-tagged\n     *   seq = OpenSSL::ASN1::Sequence.new( [int] )\n     *   der = seq.to_der\n     *   asn1 = OpenSSL::ASN1.decode(der)\n     *   # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0\n     *   #              @indefinite_length=false,\n     *   #              @tag=16,\n     *   #              @tag_class=:UNIVERSAL,\n     *   #              @tagging=nil,\n     *   #              @value=\n     *   #                [#<OpenSSL::ASN1::ASN1Data:0x87326f4\n     *   #                   @indefinite_length=false,\n     *   #                   @tag=0,\n     *   #                   @tag_class=:CONTEXT_SPECIFIC,\n     *   #                   @value=\n     *   #                     [#<OpenSSL::ASN1::Integer:0x85bf308\n     *   #                        @indefinite_length=false,\n     *   #                        @tag=2,\n     *   #                        @tag_class=:UNIVERSAL\n     *   #                        @tagging=nil,\n     *   #                        @value=1>]>]>\n     *   int2 = asn1.value[0].value[0]\n     *   puts int2.value # => 1\n     */\n    cASN1Data = rb_define_class_under(mASN1, \"ASN1Data\", rb_cObject);\n    /*\n     * Carries the value of a ASN.1 type.\n     * Please confer Constructive and Primitive for the mappings between\n     * ASN.1 data types and Ruby classes.\n     */\n    rb_attr(cASN1Data, rb_intern(\"value\"), 1, 1, 0);\n    /*\n     * An Integer representing the tag number of this ASN1Data. Never +nil+.\n     */\n    rb_attr(cASN1Data, rb_intern(\"tag\"), 1, 1, 0);\n    /*\n     * A Symbol representing the tag class of this ASN1Data. Never +nil+.\n     * See ASN1Data for possible values.\n     */\n    rb_attr(cASN1Data, rb_intern(\"tag_class\"), 1, 1, 0);\n    /*\n     * Never +nil+. A boolean value indicating whether the encoding uses\n     * indefinite length (in the case of parsing) or whether an indefinite\n     * length form shall be used (in the encoding case).\n     * In DER, every value uses definite length form. But in scenarios where\n     * large amounts of data need to be transferred it might be desirable to\n     * have some kind of streaming support available.\n     * For example, huge OCTET STRINGs are preferably sent in smaller-sized\n     * chunks, each at a time.\n     * This is possible in BER by setting the length bytes of an encoding\n     * to zero and by this indicating that the following value will be\n     * sent in chunks. Indefinite length encodings are always constructed.\n     * The end of such a stream of chunks is indicated by sending a EOC\n     * (End of Content) tag. SETs and SEQUENCEs may use an indefinite length\n     * encoding, but also primitive types such as e.g. OCTET STRINGS or\n     * BIT STRINGS may leverage this functionality (cf. ITU-T X.690).\n     */\n    rb_attr(cASN1Data, rb_intern(\"indefinite_length\"), 1, 1, 0);\n    rb_define_alias(cASN1Data, \"infinite_length\", \"indefinite_length\");\n    rb_define_alias(cASN1Data, \"infinite_length=\", \"indefinite_length=\");\n    rb_define_method(cASN1Data, \"initialize\", ossl_asn1data_initialize, 3);\n    rb_define_method(cASN1Data, \"to_der\", ossl_asn1data_to_der, 0);\n\n    /* Document-class: OpenSSL::ASN1::Primitive\n     *\n     * The parent class for all primitive encodings. Attributes are the same as\n     * for ASN1Data, with the addition of _tagging_.\n     * Primitive values can never be encoded with indefinite length form, thus\n     * it is not possible to set the _indefinite_length_ attribute for Primitive\n     * and its sub-classes.\n     *\n     * == Primitive sub-classes and their mapping to Ruby classes\n     * * OpenSSL::ASN1::EndOfContent    <=> _value_ is always +nil+\n     * * OpenSSL::ASN1::Boolean         <=> _value_ is +true+ or +false+\n     * * OpenSSL::ASN1::Integer         <=> _value_ is an OpenSSL::BN\n     * * OpenSSL::ASN1::BitString       <=> _value_ is a String\n     * * OpenSSL::ASN1::OctetString     <=> _value_ is a String\n     * * OpenSSL::ASN1::Null            <=> _value_ is always +nil+\n     * * OpenSSL::ASN1::Object          <=> _value_ is a String\n     * * OpenSSL::ASN1::Enumerated      <=> _value_ is an OpenSSL::BN\n     * * OpenSSL::ASN1::UTF8String      <=> _value_ is a String\n     * * OpenSSL::ASN1::NumericString   <=> _value_ is a String\n     * * OpenSSL::ASN1::PrintableString <=> _value_ is a String\n     * * OpenSSL::ASN1::T61String       <=> _value_ is a String\n     * * OpenSSL::ASN1::VideotexString  <=> _value_ is a String\n     * * OpenSSL::ASN1::IA5String       <=> _value_ is a String\n     * * OpenSSL::ASN1::UTCTime         <=> _value_ is a Time\n     * * OpenSSL::ASN1::GeneralizedTime <=> _value_ is a Time\n     * * OpenSSL::ASN1::GraphicString   <=> _value_ is a String\n     * * OpenSSL::ASN1::ISO64String     <=> _value_ is a String\n     * * OpenSSL::ASN1::GeneralString   <=> _value_ is a String\n     * * OpenSSL::ASN1::UniversalString <=> _value_ is a String\n     * * OpenSSL::ASN1::BMPString       <=> _value_ is a String\n     *\n     * == OpenSSL::ASN1::BitString\n     *\n     * === Additional attributes\n     * _unused_bits_: if the underlying BIT STRING's\n     * length is a multiple of 8 then _unused_bits_ is 0. Otherwise\n     * _unused_bits_ indicates the number of bits that are to be ignored in\n     * the final octet of the BitString's _value_.\n     *\n     * == OpenSSL::ASN1::ObjectId\n     *\n     * NOTE: While OpenSSL::ASN1::ObjectId.new will allocate a new ObjectId,\n     * it is not typically allocated this way, but rather that are received from\n     * parsed ASN1 encodings.\n     *\n     * === Additional attributes\n     * * _sn_: the short name as defined in <openssl/objects.h>.\n     * * _ln_: the long name as defined in <openssl/objects.h>.\n     * * _oid_: the object identifier as a String, e.g. \"1.2.3.4.5\"\n     * * _short_name_: alias for _sn_.\n     * * _long_name_: alias for _ln_.\n     *\n     * == Examples\n     * With the Exception of OpenSSL::ASN1::EndOfContent, each Primitive class\n     * constructor takes at least one parameter, the _value_.\n     *\n     * === Creating EndOfContent\n     *   eoc = OpenSSL::ASN1::EndOfContent.new\n     *\n     * === Creating any other Primitive\n     *   prim = <class>.new(value) # <class> being one of the sub-classes except EndOfContent\n     *   prim_zero_tagged_implicit = <class>.new(value, 0, :IMPLICIT)\n     *   prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)\n     */\n    cASN1Primitive = rb_define_class_under(mASN1, \"Primitive\", cASN1Data);\n    /*\n     * May be used as a hint for encoding a value either implicitly or\n     * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.\n     * _tagging_ is not set when a ASN.1 structure is parsed using\n     * OpenSSL::ASN1.decode.\n     */\n    rb_attr(cASN1Primitive, rb_intern(\"tagging\"), 1, 1, Qtrue);\n    rb_undef_method(cASN1Primitive, \"indefinite_length=\");\n    rb_undef_method(cASN1Primitive, \"infinite_length=\");\n    rb_define_method(cASN1Primitive, \"initialize\", ossl_asn1_initialize, -1);\n    rb_define_method(cASN1Primitive, \"to_der\", ossl_asn1prim_to_der, 0);\n\n    /* Document-class: OpenSSL::ASN1::Constructive\n     *\n     * The parent class for all constructed encodings. The _value_ attribute\n     * of a Constructive is always an Array. Attributes are the same as\n     * for ASN1Data, with the addition of _tagging_.\n     *\n     * == SET and SEQUENCE\n     *\n     * Most constructed encodings come in the form of a SET or a SEQUENCE.\n     * These encodings are represented by one of the two sub-classes of\n     * Constructive:\n     * * OpenSSL::ASN1::Set\n     * * OpenSSL::ASN1::Sequence\n     * Please note that tagged sequences and sets are still parsed as\n     * instances of ASN1Data. Find further details on tagged values\n     * there.\n     *\n     * === Example - constructing a SEQUENCE\n     *   int = OpenSSL::ASN1::Integer.new(1)\n     *   str = OpenSSL::ASN1::PrintableString.new('abc')\n     *   sequence = OpenSSL::ASN1::Sequence.new( [ int, str ] )\n     *\n     * === Example - constructing a SET\n     *   int = OpenSSL::ASN1::Integer.new(1)\n     *   str = OpenSSL::ASN1::PrintableString.new('abc')\n     *   set = OpenSSL::ASN1::Set.new( [ int, str ] )\n     */\n    cASN1Constructive = rb_define_class_under(mASN1,\"Constructive\", cASN1Data);\n    rb_include_module(cASN1Constructive, rb_mEnumerable);\n    /*\n     * May be used as a hint for encoding a value either implicitly or\n     * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.\n     * _tagging_ is not set when a ASN.1 structure is parsed using\n     * OpenSSL::ASN1.decode.\n     */\n    rb_attr(cASN1Constructive, rb_intern(\"tagging\"), 1, 1, Qtrue);\n    rb_define_method(cASN1Constructive, \"initialize\", ossl_asn1_initialize, -1);\n    rb_define_method(cASN1Constructive, \"to_der\", ossl_asn1cons_to_der, 0);\n    rb_define_method(cASN1Constructive, \"each\", ossl_asn1cons_each, 0);\n\n#define OSSL_ASN1_DEFINE_CLASS(name, super) \\\ndo{\\\n    cASN1##name = rb_define_class_under(mASN1, #name, cASN1##super);\\\n    rb_define_module_function(mASN1, #name, ossl_asn1_##name, -1);\\\n}while(0)\n\n    OSSL_ASN1_DEFINE_CLASS(Boolean, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(Integer, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(Enumerated, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(BitString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(OctetString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(UTF8String, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(NumericString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(PrintableString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(T61String, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(VideotexString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(IA5String, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(GraphicString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(ISO64String, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(GeneralString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(UniversalString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(BMPString, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(Null, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(ObjectId, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(UTCTime, Primitive);\n    OSSL_ASN1_DEFINE_CLASS(GeneralizedTime, Primitive);\n\n    OSSL_ASN1_DEFINE_CLASS(Sequence, Constructive);\n    OSSL_ASN1_DEFINE_CLASS(Set, Constructive);\n\n    OSSL_ASN1_DEFINE_CLASS(EndOfContent, Data);\n\n\n    /* Document-class: OpenSSL::ASN1::ObjectId\n     *\n     * Represents the primitive object id for OpenSSL::ASN1\n     */\n#if 0\n    cASN1ObjectId = rb_define_class_under(mASN1, \"ObjectId\", cASN1Primitive);  /* let rdoc know */\n#endif\n    rb_define_singleton_method(cASN1ObjectId, \"register\", ossl_asn1obj_s_register, 3);\n    rb_define_method(cASN1ObjectId, \"sn\", ossl_asn1obj_get_sn, 0);\n    rb_define_method(cASN1ObjectId, \"ln\", ossl_asn1obj_get_ln, 0);\n    rb_define_method(cASN1ObjectId, \"oid\", ossl_asn1obj_get_oid, 0);\n    rb_define_alias(cASN1ObjectId, \"short_name\", \"sn\");\n    rb_define_alias(cASN1ObjectId, \"long_name\", \"ln\");\n    rb_define_method(cASN1ObjectId, \"==\", ossl_asn1obj_eq, 1);\n    rb_attr(cASN1BitString, rb_intern(\"unused_bits\"), 1, 1, 0);\n\n    rb_define_method(cASN1EndOfContent, \"initialize\", ossl_asn1eoc_initialize, 0);\n    rb_define_method(cASN1EndOfContent, \"to_der\", ossl_asn1eoc_to_der, 0);\n\n    class_tag_map = rb_hash_new();\n    rb_gc_register_mark_object(class_tag_map);\n    rb_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC));\n    rb_hash_aset(class_tag_map, cASN1Boolean, INT2NUM(V_ASN1_BOOLEAN));\n    rb_hash_aset(class_tag_map, cASN1Integer, INT2NUM(V_ASN1_INTEGER));\n    rb_hash_aset(class_tag_map, cASN1BitString, INT2NUM(V_ASN1_BIT_STRING));\n    rb_hash_aset(class_tag_map, cASN1OctetString, INT2NUM(V_ASN1_OCTET_STRING));\n    rb_hash_aset(class_tag_map, cASN1Null, INT2NUM(V_ASN1_NULL));\n    rb_hash_aset(class_tag_map, cASN1ObjectId, INT2NUM(V_ASN1_OBJECT));\n    rb_hash_aset(class_tag_map, cASN1Enumerated, INT2NUM(V_ASN1_ENUMERATED));\n    rb_hash_aset(class_tag_map, cASN1UTF8String, INT2NUM(V_ASN1_UTF8STRING));\n    rb_hash_aset(class_tag_map, cASN1Sequence, INT2NUM(V_ASN1_SEQUENCE));\n    rb_hash_aset(class_tag_map, cASN1Set, INT2NUM(V_ASN1_SET));\n    rb_hash_aset(class_tag_map, cASN1NumericString, INT2NUM(V_ASN1_NUMERICSTRING));\n    rb_hash_aset(class_tag_map, cASN1PrintableString, INT2NUM(V_ASN1_PRINTABLESTRING));\n    rb_hash_aset(class_tag_map, cASN1T61String, INT2NUM(V_ASN1_T61STRING));\n    rb_hash_aset(class_tag_map, cASN1VideotexString, INT2NUM(V_ASN1_VIDEOTEXSTRING));\n    rb_hash_aset(class_tag_map, cASN1IA5String, INT2NUM(V_ASN1_IA5STRING));\n    rb_hash_aset(class_tag_map, cASN1UTCTime, INT2NUM(V_ASN1_UTCTIME));\n    rb_hash_aset(class_tag_map, cASN1GeneralizedTime, INT2NUM(V_ASN1_GENERALIZEDTIME));\n    rb_hash_aset(class_tag_map, cASN1GraphicString, INT2NUM(V_ASN1_GRAPHICSTRING));\n    rb_hash_aset(class_tag_map, cASN1ISO64String, INT2NUM(V_ASN1_ISO64STRING));\n    rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));\n    rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));\n    rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));\n    rb_obj_freeze(class_tag_map);\n\n    id_each = rb_intern_const(\"each\");\n}\n"
  },
  {
    "path": "ext/openssl/ossl_asn1.h",
    "content": "/*\n * 'OpenSSL for Ruby' team members\n * Copyright (C) 2003\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_ASN1_H_)\n#define _OSSL_ASN1_H_\n\n/*\n * ASN1_DATE conversions\n */\nVALUE asn1time_to_time(const ASN1_TIME *);\n/* Splits VALUE to seconds and offset days. VALUE is typically a Time or an\n * Integer. This is used when updating ASN1_*TIME with ASN1_TIME_adj() or\n * X509_time_adj_ex(). We can't use ASN1_TIME_set() and X509_time_adj() because\n * they have the Year 2038 issue on sizeof(time_t) == 4 environment */\nvoid ossl_time_split(VALUE, time_t *, int *);\n\n/*\n * ASN1_STRING conversions\n */\nVALUE asn1str_to_str(const ASN1_STRING *);\n\n/*\n * ASN1_INTEGER conversions\n */\nVALUE asn1integer_to_num(const ASN1_INTEGER *);\nASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *);\n\n/*\n * ASN1_OBJECT conversions\n */\nASN1_OBJECT *ossl_to_asn1obj(VALUE obj);\n/*\n * Returns the short name if available, the dotted decimal notation otherwise.\n * This is the most common way to return ASN1_OBJECT to Ruby.\n */\nVALUE ossl_asn1obj_to_string(const ASN1_OBJECT *a1obj);\n/*\n * However, some places use long names instead. This is likely unintentional,\n * but we keep the current behavior in existing methods.\n */\nVALUE ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *a1obj);\n\n/*\n * ASN1 module\n */\nextern VALUE mASN1;\n\nextern VALUE cASN1Data;\n\nvoid Init_ossl_asn1(void);\n\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_bio.c",
    "content": "/*\n * 'OpenSSL for Ruby' team members\n * Copyright (C) 2003\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\nBIO *\nossl_obj2bio(volatile VALUE *pobj)\n{\n    VALUE obj = *pobj;\n    BIO *bio;\n\n    if (RB_TYPE_P(obj, T_FILE))\n        obj = rb_funcallv(obj, rb_intern(\"read\"), 0, NULL);\n    StringValue(obj);\n    bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj));\n    if (!bio)\n        ossl_raise(eOSSLError, \"BIO_new_mem_buf\");\n    *pobj = obj;\n    return bio;\n}\n\nVALUE\nossl_membio2str(BIO *bio)\n{\n    VALUE ret;\n    int state;\n    BUF_MEM *buf;\n\n    if (BIO_get_mem_ptr(bio, &buf) <= 0) {\n        BIO_free(bio);\n        ossl_raise(eOSSLError, \"BIO_get_mem_ptr\");\n    }\n\n    ret = ossl_str_new(buf->data, buf->length, &state);\n    BIO_free(bio);\n    if (state)\n        rb_jump_tag(state);\n\n    return ret;\n}\n"
  },
  {
    "path": "ext/openssl/ossl_bio.h",
    "content": "/*\n * 'OpenSSL for Ruby' team members\n * Copyright (C) 2003\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_BIO_H_)\n#define _OSSL_BIO_H_\n\nBIO *ossl_obj2bio(volatile VALUE *);\nVALUE ossl_membio2str(BIO*);\n\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_bn.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Technorama team <oss-ruby@technorama.net>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n/* modified by Michal Rokos <m.rokos@sh.cvut.cz> */\n#include \"ossl.h\"\n\n#define NewBN(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)\n#define SetBN(obj, bn) do { \\\n    if (!(bn)) { \\\n        ossl_raise(rb_eRuntimeError, \"BN wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (bn); \\\n} while (0)\n\n#define GetBN(obj, bn) do { \\\n    TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \\\n    if (!(bn)) { \\\n        ossl_raise(rb_eRuntimeError, \"BN wasn't initialized!\"); \\\n    } \\\n} while (0)\n\nstatic void\nossl_bn_free(void *ptr)\n{\n    BN_clear_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_bn_type = {\n    \"OpenSSL/BN\",\n    {\n        0, ossl_bn_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,\n};\n\n/*\n * Classes\n */\nVALUE cBN;\n\n/* Document-class: OpenSSL::BNError\n *\n * Generic Error for all of OpenSSL::BN (big num)\n */\nstatic VALUE eBNError;\n\n/*\n * Public\n */\nVALUE\nossl_bn_new(const BIGNUM *bn)\n{\n    BIGNUM *newbn;\n    VALUE obj;\n\n    obj = NewBN(cBN);\n    newbn = BN_dup(bn);\n    if (!newbn)\n        ossl_raise(eBNError, \"BN_dup\");\n    SetBN(obj, newbn);\n\n    return obj;\n}\n\nstatic BIGNUM *\ninteger_to_bnptr(VALUE obj, BIGNUM *orig)\n{\n    BIGNUM *bn;\n\n    if (FIXNUM_P(obj)) {\n        long i;\n        unsigned char bin[sizeof(long)];\n        long n = FIX2LONG(obj);\n        unsigned long un = labs(n);\n\n        for (i = sizeof(long) - 1; 0 <= i; i--) {\n            bin[i] = un & 0xff;\n            un >>= 8;\n        }\n\n        bn = BN_bin2bn(bin, sizeof(bin), orig);\n        if (!bn)\n            ossl_raise(eBNError, \"BN_bin2bn\");\n        if (n < 0)\n            BN_set_negative(bn, 1);\n    }\n    else { /* assuming Bignum */\n        size_t len = rb_absint_size(obj, NULL);\n        unsigned char *bin;\n        VALUE buf;\n        int sign;\n\n        if (INT_MAX < len) {\n            rb_raise(eBNError, \"bignum too long\");\n        }\n        bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);\n        sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);\n\n        bn = BN_bin2bn(bin, (int)len, orig);\n        ALLOCV_END(buf);\n        if (!bn)\n            ossl_raise(eBNError, \"BN_bin2bn\");\n        if (sign < 0)\n            BN_set_negative(bn, 1);\n    }\n\n    return bn;\n}\n\nstatic VALUE\ntry_convert_to_bn(VALUE obj)\n{\n    BIGNUM *bn;\n    VALUE newobj = Qnil;\n\n    if (rb_obj_is_kind_of(obj, cBN))\n        return obj;\n    if (RB_INTEGER_TYPE_P(obj)) {\n        newobj = NewBN(cBN); /* Handle potential mem leaks */\n        bn = integer_to_bnptr(obj, NULL);\n        SetBN(newobj, bn);\n    }\n\n    return newobj;\n}\n\nBIGNUM *\nossl_bn_value_ptr(volatile VALUE *ptr)\n{\n    VALUE tmp;\n    BIGNUM *bn;\n\n    tmp = try_convert_to_bn(*ptr);\n    if (NIL_P(tmp))\n        ossl_raise(rb_eTypeError, \"Cannot convert into OpenSSL::BN\");\n    GetBN(tmp, bn);\n    *ptr = tmp;\n\n    return bn;\n}\n\n/*\n * Private\n */\n\n#ifdef HAVE_RB_EXT_RACTOR_SAFE\nstatic void\nossl_bn_ctx_free(void *ptr)\n{\n    BN_CTX *ctx = (BN_CTX *)ptr;\n    BN_CTX_free(ctx);\n}\n\nstatic struct rb_ractor_local_storage_type ossl_bn_ctx_key_type = {\n    NULL, // mark\n    ossl_bn_ctx_free,\n};\n\nstatic rb_ractor_local_key_t ossl_bn_ctx_key;\n\nBN_CTX *\nossl_bn_ctx_get(void)\n{\n    // stored in ractor local storage\n\n    BN_CTX *ctx = rb_ractor_local_storage_ptr(ossl_bn_ctx_key);\n    if (!ctx) {\n        if (!(ctx = BN_CTX_new())) {\n            ossl_raise(rb_eRuntimeError, \"Cannot init BN_CTX\");\n        }\n        rb_ractor_local_storage_ptr_set(ossl_bn_ctx_key, ctx);\n    }\n    return ctx;\n}\n#else\n// for ruby 2.x\nstatic BN_CTX *gv_ossl_bn_ctx;\n\nBN_CTX *\nossl_bn_ctx_get(void)\n{\n    if (gv_ossl_bn_ctx == NULL) {\n        if (!(gv_ossl_bn_ctx = BN_CTX_new())) {\n            ossl_raise(rb_eRuntimeError, \"Cannot init BN_CTX\");\n        }\n    }\n    return gv_ossl_bn_ctx;\n}\n\nvoid\nossl_bn_ctx_free(void)\n{\n    BN_CTX_free(gv_ossl_bn_ctx);\n    gv_ossl_bn_ctx = NULL;\n}\n#endif\n\nstatic VALUE\nossl_bn_alloc(VALUE klass)\n{\n    BIGNUM *bn;\n    VALUE obj = NewBN(klass);\n\n    if (!(bn = BN_new())) {\n        ossl_raise(eBNError, NULL);\n    }\n    SetBN(obj, bn);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    OpenSSL::BN.new(bn) -> aBN\n *    OpenSSL::BN.new(integer) -> aBN\n *    OpenSSL::BN.new(string, base = 10) -> aBN\n *\n * Construct a new \\OpenSSL BIGNUM object.\n *\n * If +bn+ is an Integer or OpenSSL::BN, a new instance of OpenSSL::BN\n * representing the same value is returned. See also Integer#to_bn for the\n * short-hand.\n *\n * If a String is given, the content will be parsed according to +base+.\n *\n * +string+::\n *   The string to be parsed.\n * +base+::\n *   The format. Must be one of the following:\n *   - +0+  - MPI format. See the man page BN_mpi2bn(3) for details.\n *   - +2+  - Variable-length and big-endian binary encoding of a positive\n *     number.\n *   - +10+ - Decimal number representation, with a leading '-' for a negative\n *     number.\n *   - +16+ - Hexadecimal number representation, with a leading '-' for a\n *     negative number.\n */\nstatic VALUE\nossl_bn_initialize(int argc, VALUE *argv, VALUE self)\n{\n    BIGNUM *bn;\n    VALUE str, bs;\n    int base = 10;\n    char *ptr;\n\n    if (rb_scan_args(argc, argv, \"11\", &str, &bs) == 2) {\n        base = NUM2INT(bs);\n    }\n\n    if (NIL_P(str)) {\n        ossl_raise(rb_eArgError, \"invalid argument\");\n    }\n\n    rb_check_frozen(self);\n    if (RB_INTEGER_TYPE_P(str)) {\n        GetBN(self, bn);\n        integer_to_bnptr(str, bn);\n\n        return self;\n    }\n\n    if (RTEST(rb_obj_is_kind_of(str, cBN))) {\n        BIGNUM *other;\n\n        GetBN(self, bn);\n        GetBN(str, other); /* Safe - we checked kind_of? above */\n        if (!BN_copy(bn, other)) {\n            ossl_raise(eBNError, NULL);\n        }\n        return self;\n    }\n\n    GetBN(self, bn);\n    switch (base) {\n      case 0:\n        ptr = StringValuePtr(str);\n        if (!BN_mpi2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {\n            ossl_raise(eBNError, NULL);\n        }\n        break;\n      case 2:\n        ptr = StringValuePtr(str);\n        if (!BN_bin2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {\n            ossl_raise(eBNError, NULL);\n        }\n        break;\n      case 10:\n        if (!BN_dec2bn(&bn, StringValueCStr(str))) {\n            ossl_raise(eBNError, NULL);\n        }\n        break;\n      case 16:\n        if (!BN_hex2bn(&bn, StringValueCStr(str))) {\n            ossl_raise(eBNError, NULL);\n        }\n        break;\n      default:\n        ossl_raise(rb_eArgError, \"invalid radix %d\", base);\n    }\n    return self;\n}\n\n/*\n * call-seq:\n *    bn.to_s(base = 10) -> string\n *\n * Returns the string representation of the bignum.\n *\n * BN.new can parse the encoded string to convert back into an OpenSSL::BN.\n *\n * +base+::\n *   The format. Must be one of the following:\n *   - +0+  - MPI format. See the man page BN_bn2mpi(3) for details.\n *   - +2+  - Variable-length and big-endian binary encoding. The sign of\n *     the bignum is ignored.\n *   - +10+ - Decimal number representation, with a leading '-' for a negative\n *     bignum.\n *   - +16+ - Hexadecimal number representation, with a leading '-' for a\n *     negative bignum.\n */\nstatic VALUE\nossl_bn_to_s(int argc, VALUE *argv, VALUE self)\n{\n    BIGNUM *bn;\n    VALUE str, bs;\n    int base = 10, len;\n    char *buf;\n\n    if (rb_scan_args(argc, argv, \"01\", &bs) == 1) {\n        base = NUM2INT(bs);\n    }\n    GetBN(self, bn);\n    switch (base) {\n      case 0:\n        len = BN_bn2mpi(bn, NULL);\n        str = rb_str_new(0, len);\n        if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)\n            ossl_raise(eBNError, NULL);\n        break;\n      case 2:\n        len = BN_num_bytes(bn);\n        str = rb_str_new(0, len);\n        if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)\n            ossl_raise(eBNError, NULL);\n        break;\n      case 10:\n        if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);\n        str = ossl_buf2str(buf, rb_long2int(strlen(buf)));\n        break;\n      case 16:\n        if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);\n        str = ossl_buf2str(buf, rb_long2int(strlen(buf)));\n        break;\n      default:\n        ossl_raise(rb_eArgError, \"invalid radix %d\", base);\n    }\n\n    return str;\n}\n\n/*\n * call-seq:\n *    bn.to_i => integer\n */\nstatic VALUE\nossl_bn_to_i(VALUE self)\n{\n    BIGNUM *bn;\n    char *txt;\n    VALUE num;\n\n    GetBN(self, bn);\n\n    if (!(txt = BN_bn2hex(bn))) {\n        ossl_raise(eBNError, NULL);\n    }\n    num = rb_cstr_to_inum(txt, 16, Qtrue);\n    OPENSSL_free(txt);\n\n    return num;\n}\n\nstatic VALUE\nossl_bn_to_bn(VALUE self)\n{\n    return self;\n}\n\nstatic VALUE\nossl_bn_coerce(VALUE self, VALUE other)\n{\n    switch(TYPE(other)) {\n      case T_STRING:\n        self = ossl_bn_to_s(0, NULL, self);\n        break;\n      case T_FIXNUM:\n      case T_BIGNUM:\n        self = ossl_bn_to_i(self);\n        break;\n      default:\n        if (!RTEST(rb_obj_is_kind_of(other, cBN))) {\n            ossl_raise(rb_eTypeError, \"Don't know how to coerce\");\n        }\n    }\n    return rb_assoc_new(other, self);\n}\n\n#define BIGNUM_BOOL1(func)                              \\\n    static VALUE                                        \\\n    ossl_bn_##func(VALUE self)                          \\\n    {                                                   \\\n        BIGNUM *bn;                                     \\\n        GetBN(self, bn);                                \\\n        if (BN_##func(bn)) {                            \\\n            return Qtrue;                               \\\n        }                                               \\\n        return Qfalse;                                  \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#zero?\n * call-seq:\n *   bn.zero? => true | false\n */\nBIGNUM_BOOL1(is_zero)\n\n/*\n * Document-method: OpenSSL::BN#one?\n * call-seq:\n *   bn.one? => true | false\n */\nBIGNUM_BOOL1(is_one)\n\n/*\n * Document-method: OpenSSL::BN#odd?\n * call-seq:\n *   bn.odd? => true | false\n */\nBIGNUM_BOOL1(is_odd)\n\n/*\n * call-seq:\n *   bn.negative? => true | false\n */\nstatic VALUE\nossl_bn_is_negative(VALUE self)\n{\n    BIGNUM *bn;\n\n    GetBN(self, bn);\n    if (BN_is_zero(bn))\n        return Qfalse;\n    return BN_is_negative(bn) ? Qtrue : Qfalse;\n}\n\n#define BIGNUM_1c(func)                                 \\\n    static VALUE                                        \\\n    ossl_bn_##func(VALUE self)                          \\\n    {                                                   \\\n        BIGNUM *bn, *result;                            \\\n        VALUE obj;                                      \\\n        GetBN(self, bn);                                \\\n        obj = NewBN(rb_obj_class(self));                \\\n        if (!(result = BN_new())) {                     \\\n            ossl_raise(eBNError, NULL);                 \\\n        }                                               \\\n        if (BN_##func(result, bn, ossl_bn_ctx) <= 0) {  \\\n            BN_free(result);                            \\\n            ossl_raise(eBNError, NULL);                 \\\n        }                                               \\\n        SetBN(obj, result);                             \\\n        return obj;                                     \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#sqr\n * call-seq:\n *   bn.sqr => aBN\n */\nBIGNUM_1c(sqr)\n\n#define BIGNUM_2(func)                                  \\\n    static VALUE                                        \\\n    ossl_bn_##func(VALUE self, VALUE other)             \\\n    {                                                   \\\n        BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;   \\\n        VALUE obj;                                      \\\n        GetBN(self, bn1);                               \\\n        obj = NewBN(rb_obj_class(self));                \\\n        if (!(result = BN_new())) {                     \\\n            ossl_raise(eBNError, NULL);                 \\\n        }                                               \\\n        if (BN_##func(result, bn1, bn2) <= 0) {         \\\n            BN_free(result);                            \\\n            ossl_raise(eBNError, NULL);                 \\\n        }                                               \\\n        SetBN(obj, result);                             \\\n        return obj;                                     \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#+\n * call-seq:\n *   bn + bn2 => aBN\n */\nBIGNUM_2(add)\n\n/*\n * Document-method: OpenSSL::BN#-\n * call-seq:\n *   bn - bn2 => aBN\n */\nBIGNUM_2(sub)\n\n#define BIGNUM_2c(func)                                         \\\n    static VALUE                                                \\\n    ossl_bn_##func(VALUE self, VALUE other)                     \\\n    {                                                           \\\n        BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;           \\\n        VALUE obj;                                              \\\n        GetBN(self, bn1);                                       \\\n        obj = NewBN(rb_obj_class(self));                        \\\n        if (!(result = BN_new())) {                             \\\n            ossl_raise(eBNError, NULL);                         \\\n        }                                                       \\\n        if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) {    \\\n            BN_free(result);                                    \\\n            ossl_raise(eBNError, NULL);                         \\\n        }                                                       \\\n        SetBN(obj, result);                                     \\\n        return obj;                                             \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#*\n * call-seq:\n *   bn * bn2 => aBN\n */\nBIGNUM_2c(mul)\n\n/*\n * Document-method: OpenSSL::BN#%\n * call-seq:\n *   bn % bn2 => aBN\n */\nBIGNUM_2c(mod)\n\n/*\n * Document-method: OpenSSL::BN#**\n * call-seq:\n *   bn ** bn2 => aBN\n */\nBIGNUM_2c(exp)\n\n/*\n * Document-method: OpenSSL::BN#gcd\n * call-seq:\n *   bn.gcd(bn2) => aBN\n */\nBIGNUM_2c(gcd)\n\n/*\n * Document-method: OpenSSL::BN#mod_sqr\n * call-seq:\n *   bn.mod_sqr(bn2) => aBN\n */\nBIGNUM_2c(mod_sqr)\n\n#define BIGNUM_2cr(func)                                        \\\n    static VALUE                                                \\\n    ossl_bn_##func(VALUE self, VALUE other)                     \\\n    {                                                           \\\n        BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;           \\\n        VALUE obj;                                              \\\n        GetBN(self, bn1);                                       \\\n        obj = NewBN(rb_obj_class(self));                        \\\n        if (!(result = BN_##func(NULL, bn1, bn2, ossl_bn_ctx))) \\\n            ossl_raise(eBNError, NULL);                         \\\n        SetBN(obj, result);                                     \\\n        return obj;                                             \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#mod_sqrt\n * call-seq:\n *   bn.mod_sqrt(bn2) => aBN\n */\nBIGNUM_2cr(mod_sqrt)\n\n/*\n * Document-method: OpenSSL::BN#mod_inverse\n * call-seq:\n *    bn.mod_inverse(bn2) => aBN\n */\nBIGNUM_2cr(mod_inverse)\n\n/*\n * call-seq:\n *    bn1 / bn2 => [result, remainder]\n *\n * Division of OpenSSL::BN instances\n */\nstatic VALUE\nossl_bn_div(VALUE self, VALUE other)\n{\n    BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;\n    VALUE klass, obj1, obj2;\n\n    GetBN(self, bn1);\n\n    klass = rb_obj_class(self);\n    obj1 = NewBN(klass);\n    obj2 = NewBN(klass);\n    if (!(r1 = BN_new())) {\n        ossl_raise(eBNError, NULL);\n    }\n    if (!(r2 = BN_new())) {\n        BN_free(r1);\n        ossl_raise(eBNError, NULL);\n    }\n    if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {\n        BN_free(r1);\n        BN_free(r2);\n        ossl_raise(eBNError, NULL);\n    }\n    SetBN(obj1, r1);\n    SetBN(obj2, r2);\n\n    return rb_ary_new3(2, obj1, obj2);\n}\n\n#define BIGNUM_3c(func)                                         \\\n    static VALUE                                                \\\n    ossl_bn_##func(VALUE self, VALUE other1, VALUE other2)      \\\n    {                                                           \\\n        BIGNUM *bn1, *bn2 = GetBNPtr(other1);                   \\\n        BIGNUM *bn3 = GetBNPtr(other2), *result;                \\\n        VALUE obj;                                              \\\n        GetBN(self, bn1);                                       \\\n        obj = NewBN(rb_obj_class(self));                        \\\n        if (!(result = BN_new())) {                             \\\n            ossl_raise(eBNError, NULL);                         \\\n        }                                                       \\\n        if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \\\n            BN_free(result);                                    \\\n            ossl_raise(eBNError, NULL);                         \\\n        }                                                       \\\n        SetBN(obj, result);                                     \\\n        return obj;                                             \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#mod_add\n * call-seq:\n *   bn.mod_add(bn1, bn2) -> aBN\n */\nBIGNUM_3c(mod_add)\n\n/*\n * Document-method: OpenSSL::BN#mod_sub\n * call-seq:\n *   bn.mod_sub(bn1, bn2) -> aBN\n */\nBIGNUM_3c(mod_sub)\n\n/*\n * Document-method: OpenSSL::BN#mod_mul\n * call-seq:\n *   bn.mod_mul(bn1, bn2) -> aBN\n */\nBIGNUM_3c(mod_mul)\n\n/*\n * Document-method: OpenSSL::BN#mod_exp\n * call-seq:\n *   bn.mod_exp(bn1, bn2) -> aBN\n */\nBIGNUM_3c(mod_exp)\n\n#define BIGNUM_BIT(func)                                \\\n    static VALUE                                        \\\n    ossl_bn_##func(VALUE self, VALUE bit)               \\\n    {                                                   \\\n        BIGNUM *bn;                                     \\\n        rb_check_frozen(self);                          \\\n        GetBN(self, bn);                                \\\n        if (BN_##func(bn, NUM2INT(bit)) <= 0) {         \\\n            ossl_raise(eBNError, NULL);                 \\\n        }                                               \\\n        return self;                                    \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#set_bit!\n * call-seq:\n *   bn.set_bit!(bit) -> self\n */\nBIGNUM_BIT(set_bit)\n\n/*\n * Document-method: OpenSSL::BN#clear_bit!\n * call-seq:\n *   bn.clear_bit!(bit) -> self\n */\nBIGNUM_BIT(clear_bit)\n\n/*\n * Document-method: OpenSSL::BN#mask_bit!\n * call-seq:\n *   bn.mask_bit!(bit) -> self\n */\nBIGNUM_BIT(mask_bits)\n\n/*\n * call-seq:\n *   bn.bit_set?(bit) => true | false\n *\n * Tests bit _bit_ in _bn_ and returns +true+ if set, +false+ if not set.\n */\nstatic VALUE\nossl_bn_is_bit_set(VALUE self, VALUE bit)\n{\n    int b;\n    BIGNUM *bn;\n\n    b = NUM2INT(bit);\n    GetBN(self, bn);\n    if (BN_is_bit_set(bn, b)) {\n        return Qtrue;\n    }\n    return Qfalse;\n}\n\n#define BIGNUM_SHIFT(func)                              \\\n    static VALUE                                        \\\n    ossl_bn_##func(VALUE self, VALUE bits)              \\\n    {                                                   \\\n        BIGNUM *bn, *result;                            \\\n        int b;                                          \\\n        VALUE obj;                                      \\\n        b = NUM2INT(bits);                              \\\n        GetBN(self, bn);                                \\\n        obj = NewBN(rb_obj_class(self));                \\\n        if (!(result = BN_new())) {                     \\\n                ossl_raise(eBNError, NULL);             \\\n        }                                               \\\n        if (BN_##func(result, bn, b) <= 0) {            \\\n                BN_free(result);                        \\\n                ossl_raise(eBNError, NULL);             \\\n        }                                               \\\n        SetBN(obj, result);                             \\\n        return obj;                                     \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#<<\n * call-seq:\n *   bn << bits -> aBN\n */\nBIGNUM_SHIFT(lshift)\n\n/*\n * Document-method: OpenSSL::BN#>>\n * call-seq:\n *   bn >> bits -> aBN\n */\nBIGNUM_SHIFT(rshift)\n\n#define BIGNUM_SELF_SHIFT(func)                         \\\n    static VALUE                                        \\\n    ossl_bn_self_##func(VALUE self, VALUE bits)         \\\n    {                                                   \\\n        BIGNUM *bn;                                     \\\n        int b;                                          \\\n        rb_check_frozen(self);                          \\\n        b = NUM2INT(bits);                              \\\n        GetBN(self, bn);                                \\\n        if (BN_##func(bn, bn, b) <= 0)                  \\\n                ossl_raise(eBNError, NULL);             \\\n        return self;                                    \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#lshift!\n * call-seq:\n *   bn.lshift!(bits) -> self\n */\nBIGNUM_SELF_SHIFT(lshift)\n\n/*\n * Document-method: OpenSSL::BN#rshift!\n * call-seq:\n *   bn.rshift!(bits) -> self\n */\nBIGNUM_SELF_SHIFT(rshift)\n\n/*\n * call-seq:\n *    BN.rand(bits [, fill [, odd]]) -> aBN\n *\n * Generates a cryptographically strong pseudo-random number of +bits+.\n *\n * See also the man page BN_rand(3).\n */\nstatic VALUE\nossl_bn_s_rand(int argc, VALUE *argv, VALUE klass)\n{\n    BIGNUM *result;\n    int bottom = 0, top = 0, b;\n    VALUE bits, fill, odd, obj;\n\n    switch (rb_scan_args(argc, argv, \"12\", &bits, &fill, &odd)) {\n      case 3:\n        bottom = (odd == Qtrue) ? 1 : 0;\n        /* FALLTHROUGH */\n      case 2:\n        top = NUM2INT(fill);\n    }\n    b = NUM2INT(bits);\n    obj = NewBN(klass);\n    if (!(result = BN_new())) {\n        ossl_raise(eBNError, \"BN_new\");\n    }\n    if (BN_rand(result, b, top, bottom) <= 0) {\n        BN_free(result);\n        ossl_raise(eBNError, \"BN_rand\");\n    }\n    SetBN(obj, result);\n    return obj;\n}\n\n/*\n * call-seq:\n *    BN.rand_range(range) -> aBN\n *\n * Generates a cryptographically strong pseudo-random number in the range\n * 0...+range+.\n *\n * See also the man page BN_rand_range(3).\n */\nstatic VALUE\nossl_bn_s_rand_range(VALUE klass, VALUE range)\n{\n    BIGNUM *bn = GetBNPtr(range), *result;\n    VALUE obj = NewBN(klass);\n    if (!(result = BN_new()))\n        ossl_raise(eBNError, \"BN_new\");\n    if (BN_rand_range(result, bn) <= 0) {\n        BN_free(result);\n        ossl_raise(eBNError, \"BN_rand_range\");\n    }\n    SetBN(obj, result);\n    return obj;\n}\n\n/*\n * call-seq:\n *    BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn\n *\n * Generates a random prime number of bit length _bits_. If _safe_ is set to\n * +true+, generates a safe prime. If _add_ is specified, generates a prime that\n * fulfills condition <tt>p % add = rem</tt>.\n *\n * === Parameters\n * * _bits_ - integer\n * * _safe_ - boolean\n * * _add_ - BN\n * * _rem_ - BN\n */\nstatic VALUE\nossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)\n{\n    BIGNUM *add = NULL, *rem = NULL, *result;\n    int safe = 1, num;\n    VALUE vnum, vsafe, vadd, vrem, obj;\n\n    rb_scan_args(argc, argv, \"13\", &vnum, &vsafe, &vadd, &vrem);\n\n    num = NUM2INT(vnum);\n\n    if (vsafe == Qfalse) {\n        safe = 0;\n    }\n    if (!NIL_P(vadd)) {\n        add = GetBNPtr(vadd);\n        rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);\n    }\n    obj = NewBN(klass);\n    if (!(result = BN_new())) {\n        ossl_raise(eBNError, NULL);\n    }\n    if (!BN_generate_prime_ex(result, num, safe, add, rem, NULL)) {\n        BN_free(result);\n        ossl_raise(eBNError, NULL);\n    }\n    SetBN(obj, result);\n\n    return obj;\n}\n\n#define BIGNUM_NUM(func)                        \\\n    static VALUE                                \\\n    ossl_bn_##func(VALUE self)                  \\\n    {                                           \\\n        BIGNUM *bn;                             \\\n        GetBN(self, bn);                        \\\n        return INT2NUM(BN_##func(bn));          \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#num_bytes\n * call-seq:\n *   bn.num_bytes => integer\n */\nBIGNUM_NUM(num_bytes)\n\n/*\n * Document-method: OpenSSL::BN#num_bits\n * call-seq:\n *   bn.num_bits => integer\n */\nBIGNUM_NUM(num_bits)\n\n/* :nodoc: */\nstatic VALUE\nossl_bn_copy(VALUE self, VALUE other)\n{\n    BIGNUM *bn1, *bn2;\n\n    rb_check_frozen(self);\n\n    if (self == other) return self;\n\n    GetBN(self, bn1);\n    bn2 = GetBNPtr(other);\n\n    if (!BN_copy(bn1, bn2)) {\n        ossl_raise(eBNError, NULL);\n    }\n    return self;\n}\n\n/*\n * call-seq:\n *   +bn -> aBN\n */\nstatic VALUE\nossl_bn_uplus(VALUE self)\n{\n    VALUE obj;\n    BIGNUM *bn1, *bn2;\n\n    GetBN(self, bn1);\n    obj = NewBN(cBN);\n    bn2 = BN_dup(bn1);\n    if (!bn2)\n        ossl_raise(eBNError, \"BN_dup\");\n    SetBN(obj, bn2);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *   -bn -> aBN\n */\nstatic VALUE\nossl_bn_uminus(VALUE self)\n{\n    VALUE obj;\n    BIGNUM *bn1, *bn2;\n\n    GetBN(self, bn1);\n    obj = NewBN(cBN);\n    bn2 = BN_dup(bn1);\n    if (!bn2)\n        ossl_raise(eBNError, \"BN_dup\");\n    SetBN(obj, bn2);\n    BN_set_negative(bn2, !BN_is_negative(bn2));\n\n    return obj;\n}\n\n/*\n * call-seq:\n *   bn.abs -> aBN\n */\nstatic VALUE\nossl_bn_abs(VALUE self)\n{\n    BIGNUM *bn1;\n\n    GetBN(self, bn1);\n    if (BN_is_negative(bn1)) {\n        return ossl_bn_uminus(self);\n    }\n    else {\n        return ossl_bn_uplus(self);\n    }\n}\n\n#define BIGNUM_CMP(func)                                \\\n    static VALUE                                        \\\n    ossl_bn_##func(VALUE self, VALUE other)             \\\n    {                                                   \\\n        BIGNUM *bn1, *bn2 = GetBNPtr(other);            \\\n        GetBN(self, bn1);                               \\\n        return INT2NUM(BN_##func(bn1, bn2));            \\\n    }\n\n/*\n * Document-method: OpenSSL::BN#cmp\n * call-seq:\n *   bn.cmp(bn2) => integer\n */\n/*\n * Document-method: OpenSSL::BN#<=>\n * call-seq:\n *   bn <=> bn2 => integer\n */\nBIGNUM_CMP(cmp)\n\n/*\n * Document-method: OpenSSL::BN#ucmp\n * call-seq:\n *   bn.ucmp(bn2) => integer\n */\nBIGNUM_CMP(ucmp)\n\n/*\n *  call-seq:\n *     bn == obj => true or false\n *\n *  Returns +true+ only if _obj_ has the same value as _bn_. Contrast this\n *  with OpenSSL::BN#eql?, which requires obj to be OpenSSL::BN.\n */\nstatic VALUE\nossl_bn_eq(VALUE self, VALUE other)\n{\n    BIGNUM *bn1, *bn2;\n\n    GetBN(self, bn1);\n    other = try_convert_to_bn(other);\n    if (NIL_P(other))\n        return Qfalse;\n    GetBN(other, bn2);\n\n    if (!BN_cmp(bn1, bn2)) {\n        return Qtrue;\n    }\n    return Qfalse;\n}\n\n/*\n *  call-seq:\n *     bn.eql?(obj) => true or false\n *\n *  Returns <code>true</code> only if <i>obj</i> is a\n *  <code>OpenSSL::BN</code> with the same value as <i>bn</i>. Contrast this\n *  with OpenSSL::BN#==, which performs type conversions.\n */\nstatic VALUE\nossl_bn_eql(VALUE self, VALUE other)\n{\n    BIGNUM *bn1, *bn2;\n\n    if (!rb_obj_is_kind_of(other, cBN))\n        return Qfalse;\n    GetBN(self, bn1);\n    GetBN(other, bn2);\n\n    return BN_cmp(bn1, bn2) ? Qfalse : Qtrue;\n}\n\n/*\n *  call-seq:\n *     bn.hash => Integer\n *\n *  Returns a hash code for this object.\n *\n *  See also Object#hash.\n */\nstatic VALUE\nossl_bn_hash(VALUE self)\n{\n    BIGNUM *bn;\n    VALUE tmp, hash;\n    unsigned char *buf;\n    int len;\n\n    GetBN(self, bn);\n    len = BN_num_bytes(bn);\n    buf = ALLOCV(tmp, len);\n    if (BN_bn2bin(bn, buf) != len) {\n        ALLOCV_END(tmp);\n        ossl_raise(eBNError, \"BN_bn2bin\");\n    }\n\n    hash = ST2FIX(rb_memhash(buf, len));\n    ALLOCV_END(tmp);\n\n    return hash;\n}\n\n/*\n * call-seq:\n *    bn.prime? => true | false\n *    bn.prime?(checks) => true | false\n *\n * Performs a Miller-Rabin probabilistic primality test for +bn+.\n *\n * <b>+checks+ parameter is deprecated in version 3.0.</b> It has no effect.\n */\nstatic VALUE\nossl_bn_is_prime(int argc, VALUE *argv, VALUE self)\n{\n    BIGNUM *bn;\n    int ret;\n\n    rb_check_arity(argc, 0, 1);\n    GetBN(self, bn);\n\n#ifdef HAVE_BN_CHECK_PRIME\n    ret = BN_check_prime(bn, ossl_bn_ctx, NULL);\n    if (ret < 0)\n        ossl_raise(eBNError, \"BN_check_prime\");\n#else\n    ret = BN_is_prime_fasttest_ex(bn, BN_prime_checks, ossl_bn_ctx, 1, NULL);\n    if (ret < 0)\n        ossl_raise(eBNError, \"BN_is_prime_fasttest_ex\");\n#endif\n    return ret ? Qtrue : Qfalse;\n}\n\n/*\n * call-seq:\n *    bn.prime_fasttest? => true | false\n *    bn.prime_fasttest?(checks) => true | false\n *    bn.prime_fasttest?(checks, trial_div) => true | false\n *\n * Performs a Miller-Rabin probabilistic primality test for +bn+.\n *\n * <b>Deprecated in version 3.0.</b> Use #prime? instead.\n *\n * +checks+ and +trial_div+ parameters no longer have any effect.\n */\nstatic VALUE\nossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)\n{\n    rb_check_arity(argc, 0, 2);\n    return ossl_bn_is_prime(0, argv, self);\n}\n\n/*\n * call-seq:\n *    bn.get_flags(flags) => flags\n *\n * Returns the flags on the BN object.\n * The argument is used as a bit mask.\n *\n * === Parameters\n * * _flags_ - integer\n */\nstatic VALUE\nossl_bn_get_flags(VALUE self, VALUE arg)\n{\n    BIGNUM *bn;\n    GetBN(self, bn);\n\n    return INT2NUM(BN_get_flags(bn, NUM2INT(arg)));\n}\n\n/*\n * call-seq:\n *    bn.set_flags(flags) => nil\n *\n * Enables the flags on the BN object.\n * Currently, the flags argument can contain zero of OpenSSL::BN::CONSTTIME.\n */\nstatic VALUE\nossl_bn_set_flags(VALUE self, VALUE arg)\n{\n    BIGNUM *bn;\n    GetBN(self, bn);\n\n    rb_check_frozen(self);\n    BN_set_flags(bn, NUM2INT(arg));\n    return Qnil;\n}\n\n/*\n * INIT\n * (NOTE: ordering of methods is the same as in 'man bn')\n */\nvoid\nInit_ossl_bn(void)\n{\n#ifdef HAVE_RB_EXT_RACTOR_SAFE\n    ossl_bn_ctx_key = rb_ractor_local_storage_ptr_newkey(&ossl_bn_ctx_key_type);\n#else\n    ossl_bn_ctx_get();\n#endif\n\n    eBNError = rb_define_class_under(mOSSL, \"BNError\", eOSSLError);\n\n    cBN = rb_define_class_under(mOSSL, \"BN\", rb_cObject);\n\n    rb_define_alloc_func(cBN, ossl_bn_alloc);\n    rb_define_method(cBN, \"initialize\", ossl_bn_initialize, -1);\n\n    rb_define_method(cBN, \"initialize_copy\", ossl_bn_copy, 1);\n    rb_define_method(cBN, \"copy\", ossl_bn_copy, 1);\n\n    /* swap (=coerce?) */\n\n    rb_define_method(cBN, \"num_bytes\", ossl_bn_num_bytes, 0);\n    rb_define_method(cBN, \"num_bits\", ossl_bn_num_bits, 0);\n    /* num_bits_word */\n\n    rb_define_method(cBN, \"+@\", ossl_bn_uplus, 0);\n    rb_define_method(cBN, \"-@\", ossl_bn_uminus, 0);\n    rb_define_method(cBN, \"abs\", ossl_bn_abs, 0);\n\n    rb_define_method(cBN, \"+\", ossl_bn_add, 1);\n    rb_define_method(cBN, \"-\", ossl_bn_sub, 1);\n    rb_define_method(cBN, \"*\", ossl_bn_mul, 1);\n    rb_define_method(cBN, \"sqr\", ossl_bn_sqr, 0);\n    rb_define_method(cBN, \"/\", ossl_bn_div, 1);\n    rb_define_method(cBN, \"%\", ossl_bn_mod, 1);\n    /* nnmod */\n\n    rb_define_method(cBN, \"mod_add\", ossl_bn_mod_add, 2);\n    rb_define_method(cBN, \"mod_sub\", ossl_bn_mod_sub, 2);\n    rb_define_method(cBN, \"mod_mul\", ossl_bn_mod_mul, 2);\n    rb_define_method(cBN, \"mod_sqr\", ossl_bn_mod_sqr, 1);\n    rb_define_method(cBN, \"mod_sqrt\", ossl_bn_mod_sqrt, 1);\n    rb_define_method(cBN, \"**\", ossl_bn_exp, 1);\n    rb_define_method(cBN, \"mod_exp\", ossl_bn_mod_exp, 2);\n    rb_define_method(cBN, \"gcd\", ossl_bn_gcd, 1);\n\n    /* add_word\n     * sub_word\n     * mul_word\n     * div_word\n     * mod_word */\n\n    rb_define_method(cBN, \"cmp\", ossl_bn_cmp, 1);\n    rb_define_alias(cBN, \"<=>\", \"cmp\");\n    rb_define_method(cBN, \"ucmp\", ossl_bn_ucmp, 1);\n    rb_define_method(cBN, \"eql?\", ossl_bn_eql, 1);\n    rb_define_method(cBN, \"hash\", ossl_bn_hash, 0);\n    rb_define_method(cBN, \"==\", ossl_bn_eq, 1);\n    rb_define_alias(cBN, \"===\", \"==\");\n    rb_define_method(cBN, \"zero?\", ossl_bn_is_zero, 0);\n    rb_define_method(cBN, \"one?\", ossl_bn_is_one, 0);\n    /* is_word */\n    rb_define_method(cBN, \"odd?\", ossl_bn_is_odd, 0);\n    rb_define_method(cBN, \"negative?\", ossl_bn_is_negative, 0);\n\n    /* zero\n     * one\n     * value_one - DON'T IMPL.\n     * set_word\n     * get_word */\n\n    rb_define_singleton_method(cBN, \"rand\", ossl_bn_s_rand, -1);\n    rb_define_singleton_method(cBN, \"rand_range\", ossl_bn_s_rand_range, 1);\n    rb_define_alias(rb_singleton_class(cBN), \"pseudo_rand\", \"rand\");\n    rb_define_alias(rb_singleton_class(cBN), \"pseudo_rand_range\", \"rand_range\");\n\n    rb_define_singleton_method(cBN, \"generate_prime\", ossl_bn_s_generate_prime, -1);\n    rb_define_method(cBN, \"prime?\", ossl_bn_is_prime, -1);\n    rb_define_method(cBN, \"prime_fasttest?\", ossl_bn_is_prime_fasttest, -1);\n\n    rb_define_method(cBN, \"set_bit!\", ossl_bn_set_bit, 1);\n    rb_define_method(cBN, \"clear_bit!\", ossl_bn_clear_bit, 1);\n    rb_define_method(cBN, \"bit_set?\", ossl_bn_is_bit_set, 1);\n    rb_define_method(cBN, \"mask_bits!\", ossl_bn_mask_bits, 1);\n    rb_define_method(cBN, \"<<\", ossl_bn_lshift, 1);\n    rb_define_method(cBN, \">>\", ossl_bn_rshift, 1);\n    rb_define_method(cBN, \"lshift!\", ossl_bn_self_lshift, 1);\n    rb_define_method(cBN, \"rshift!\", ossl_bn_self_rshift, 1);\n    /* lshift1 - DON'T IMPL. */\n    /* rshift1 - DON'T IMPL. */\n\n    rb_define_method(cBN, \"get_flags\", ossl_bn_get_flags, 1);\n    rb_define_method(cBN, \"set_flags\", ossl_bn_set_flags, 1);\n\n#ifdef BN_FLG_CONSTTIME\n    rb_define_const(cBN, \"CONSTTIME\", INT2NUM(BN_FLG_CONSTTIME));\n#endif\n    /* BN_FLG_MALLOCED and BN_FLG_STATIC_DATA seems for C programming.\n     * Allowing them leads to memory leak.\n     * So, for now, they are not exported\n#ifdef BN_FLG_MALLOCED\n    rb_define_const(cBN, \"MALLOCED\", INT2NUM(BN_FLG_MALLOCED));\n#endif\n#ifdef BN_FLG_STATIC_DATA\n    rb_define_const(cBN, \"STATIC_DATA\", INT2NUM(BN_FLG_STATIC_DATA));\n#endif\n    */\n\n    /*\n     * bn2bin\n     * bin2bn\n     * bn2hex\n     * bn2dec\n     * hex2bn\n     * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s\n     * print - NOT IMPL.\n     * print_fp - NOT IMPL.\n     * bn2mpi\n     * mpi2bn\n     */\n    rb_define_method(cBN, \"to_s\", ossl_bn_to_s, -1);\n    rb_define_method(cBN, \"to_i\", ossl_bn_to_i, 0);\n    rb_define_alias(cBN, \"to_int\", \"to_i\");\n    rb_define_method(cBN, \"to_bn\", ossl_bn_to_bn, 0);\n    rb_define_method(cBN, \"coerce\", ossl_bn_coerce, 1);\n\n    /*\n     * TODO:\n     * But how to: from_bin, from_mpi? PACK?\n     * to_bin\n     * to_mpi\n     */\n\n    rb_define_method(cBN, \"mod_inverse\", ossl_bn_mod_inverse, 1);\n\n    /* RECiProcal\n     * MONTgomery */\n}\n"
  },
  {
    "path": "ext/openssl/ossl_bn.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_BN_H_)\n#define _OSSL_BN_H_\n\nextern VALUE cBN;\n\nBN_CTX *ossl_bn_ctx_get(void);\n#define ossl_bn_ctx ossl_bn_ctx_get()\n\n#define GetBNPtr(obj) ossl_bn_value_ptr(&(obj))\n\nVALUE ossl_bn_new(const BIGNUM *);\nBIGNUM *ossl_bn_value_ptr(volatile VALUE *);\nvoid Init_ossl_bn(void);\n\n\n#endif /* _OSS_BN_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_cipher.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewCipher(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_cipher_type, 0)\n#define AllocCipher(obj, ctx) do { \\\n    (ctx) = EVP_CIPHER_CTX_new(); \\\n    if (!(ctx)) \\\n        ossl_raise(rb_eRuntimeError, NULL); \\\n    RTYPEDDATA_DATA(obj) = (ctx); \\\n} while (0)\n#define GetCipherInit(obj, ctx) do { \\\n    TypedData_Get_Struct((obj), EVP_CIPHER_CTX, &ossl_cipher_type, (ctx)); \\\n} while (0)\n#define GetCipher(obj, ctx) do { \\\n    GetCipherInit((obj), (ctx)); \\\n    if (!(ctx)) { \\\n        ossl_raise(rb_eRuntimeError, \"Cipher not initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nstatic VALUE cCipher;\nstatic VALUE eCipherError;\nstatic VALUE eAuthTagError;\nstatic ID id_auth_tag_len, id_key_set, id_cipher_holder;\n\nstatic VALUE ossl_cipher_alloc(VALUE klass);\nstatic void ossl_cipher_free(void *ptr);\n\nstatic const rb_data_type_t ossl_cipher_type = {\n    \"OpenSSL/Cipher\",\n    {\n        0, ossl_cipher_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n#ifdef OSSL_USE_PROVIDER\nstatic void\nossl_evp_cipher_free(void *ptr)\n{\n    // This is safe to call against const EVP_CIPHER * returned by\n    // EVP_get_cipherbyname()\n    EVP_CIPHER_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_evp_cipher_holder_type = {\n    \"OpenSSL/EVP_CIPHER\",\n    {\n        .dfree = ossl_evp_cipher_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n#endif\n\n/*\n * PUBLIC\n */\nconst EVP_CIPHER *\nossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder)\n{\n    *holder = Qnil;\n    if (rb_obj_is_kind_of(obj, cCipher)) {\n        EVP_CIPHER_CTX *ctx;\n        GetCipher(obj, ctx);\n        EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_CIPHER_CTX_cipher(ctx);\n#ifdef OSSL_USE_PROVIDER\n        *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);\n        if (!EVP_CIPHER_up_ref(cipher))\n            ossl_raise(eCipherError, \"EVP_CIPHER_up_ref\");\n        RTYPEDDATA_DATA(*holder) = cipher;\n#endif\n        return cipher;\n    }\n\n    const char *name = StringValueCStr(obj);\n    EVP_CIPHER *cipher = (EVP_CIPHER *)EVP_get_cipherbyname(name);\n#ifdef OSSL_USE_PROVIDER\n    if (!cipher) {\n        ossl_clear_error();\n        *holder = TypedData_Wrap_Struct(0, &ossl_evp_cipher_holder_type, NULL);\n        cipher = EVP_CIPHER_fetch(NULL, name, NULL);\n        RTYPEDDATA_DATA(*holder) = cipher;\n    }\n#endif\n    if (!cipher)\n        ossl_raise(eCipherError, \"unsupported cipher algorithm: %\"PRIsVALUE,\n                   obj);\n    return cipher;\n}\n\nVALUE\nossl_cipher_new(const EVP_CIPHER *cipher)\n{\n    VALUE ret;\n    EVP_CIPHER_CTX *ctx;\n\n    // NOTE: This does not set id_cipher_holder because this function should\n    // only be called from ossl_engine.c, which will not use any\n    // reference-counted ciphers.\n    ret = ossl_cipher_alloc(cCipher);\n    AllocCipher(ret, ctx);\n    if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)\n        ossl_raise(eCipherError, NULL);\n\n    return ret;\n}\n\n/*\n * PRIVATE\n */\nstatic void\nossl_cipher_free(void *ptr)\n{\n    EVP_CIPHER_CTX_free(ptr);\n}\n\nstatic VALUE\nossl_cipher_alloc(VALUE klass)\n{\n    return NewCipher(klass);\n}\n\n/*\n *  call-seq:\n *     Cipher.new(string) -> cipher\n *\n *  The string must contain a valid cipher name like \"aes-256-cbc\".\n *\n *  A list of cipher names is available by calling OpenSSL::Cipher.ciphers.\n */\nstatic VALUE\nossl_cipher_initialize(VALUE self, VALUE str)\n{\n    EVP_CIPHER_CTX *ctx;\n    const EVP_CIPHER *cipher;\n    VALUE cipher_holder;\n\n    GetCipherInit(self, ctx);\n    if (ctx) {\n        ossl_raise(rb_eRuntimeError, \"Cipher already initialized!\");\n    }\n    cipher = ossl_evp_cipher_fetch(str, &cipher_holder);\n    AllocCipher(self, ctx);\n    if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)\n        ossl_raise(eCipherError, \"EVP_CipherInit_ex\");\n    rb_ivar_set(self, id_cipher_holder, cipher_holder);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_cipher_copy(VALUE self, VALUE other)\n{\n    EVP_CIPHER_CTX *ctx1, *ctx2;\n\n    rb_check_frozen(self);\n    if (self == other) return self;\n\n    GetCipherInit(self, ctx1);\n    if (!ctx1) {\n        AllocCipher(self, ctx1);\n    }\n    GetCipher(other, ctx2);\n    if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1)\n        ossl_raise(eCipherError, NULL);\n\n    return self;\n}\n\nstatic void\nadd_cipher_name_to_ary(const OBJ_NAME *name, void *arg)\n{\n    VALUE ary = (VALUE)arg;\n    rb_ary_push(ary, rb_str_new2(name->name));\n}\n\n/*\n *  call-seq:\n *     OpenSSL::Cipher.ciphers -> array[string...]\n *\n *  Returns the names of all available ciphers in an array.\n */\nstatic VALUE\nossl_s_ciphers(VALUE self)\n{\n    VALUE ary;\n\n    ary = rb_ary_new();\n    OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,\n                           add_cipher_name_to_ary,\n                           (void*)ary);\n\n    return ary;\n}\n\n/*\n *  call-seq:\n *     cipher.reset -> self\n *\n *  Fully resets the internal state of the Cipher. By using this, the same\n *  Cipher instance may be used several times for encryption or decryption tasks.\n *\n *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1).\n */\nstatic VALUE\nossl_cipher_reset(VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)\n        ossl_raise(eCipherError, NULL);\n\n    return self;\n}\n\nstatic VALUE\nossl_cipher_init(VALUE self, int enc)\n{\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, enc) != 1) {\n        ossl_raise(eCipherError, \"EVP_CipherInit_ex\");\n    }\n\n    rb_ivar_set(self, id_key_set, Qfalse);\n\n    return self;\n}\n\n/*\n *  call-seq:\n *     cipher.encrypt -> self\n *\n *  Initializes the Cipher for encryption.\n *\n *  Make sure to call either #encrypt or #decrypt before using the Cipher for\n *  any operation or setting any parameters.\n *\n *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).\n */\nstatic VALUE\nossl_cipher_encrypt(VALUE self)\n{\n    return ossl_cipher_init(self, 1);\n}\n\n/*\n *  call-seq:\n *     cipher.decrypt -> self\n *\n *  Initializes the Cipher for decryption.\n *\n *  Make sure to call either #encrypt or #decrypt before using the Cipher for\n *  any operation or setting any parameters.\n *\n *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).\n */\nstatic VALUE\nossl_cipher_decrypt(VALUE self)\n{\n    return ossl_cipher_init(self, 0);\n}\n\n/*\n *  call-seq:\n *     cipher.pkcs5_keyivgen(pass, salt = nil, iterations = 2048, digest = \"MD5\") -> nil\n *\n *  Generates and sets the key/IV based on a password.\n *\n *  *WARNING*: This method is deprecated and should not be used. This method\n *  corresponds to EVP_BytesToKey(), a non-standard OpenSSL extension of the\n *  legacy PKCS #5 v1.5 key derivation function. See OpenSSL::KDF for other\n *  options to derive keys from passwords.\n *\n *  === Parameters\n *  * _salt_ must be an 8 byte string if provided.\n *  * _iterations_ is an integer with a default of 2048.\n *  * _digest_ is a Digest object that defaults to 'MD5'\n */\nstatic VALUE\nossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n    const EVP_MD *digest;\n    VALUE vpass, vsalt, viter, vdigest, md_holder;\n    unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;\n    int iter;\n\n    rb_scan_args(argc, argv, \"13\", &vpass, &vsalt, &viter, &vdigest);\n    StringValue(vpass);\n    if(!NIL_P(vsalt)){\n        StringValue(vsalt);\n        if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)\n            ossl_raise(eCipherError, \"salt must be an 8-octet string\");\n        salt = (unsigned char *)RSTRING_PTR(vsalt);\n    }\n    iter = NIL_P(viter) ? 2048 : NUM2INT(viter);\n    if (iter <= 0)\n        rb_raise(rb_eArgError, \"iterations must be a positive integer\");\n    digest = NIL_P(vdigest) ? EVP_md5() : ossl_evp_md_fetch(vdigest, &md_holder);\n    GetCipher(self, ctx);\n    EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,\n                   (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);\n    if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)\n        ossl_raise(eCipherError, NULL);\n    OPENSSL_cleanse(key, sizeof key);\n    OPENSSL_cleanse(iv, sizeof iv);\n\n    rb_ivar_set(self, id_key_set, Qtrue);\n\n    return Qnil;\n}\n\nstatic int\nossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_ptr,\n                        const unsigned char *in, long in_len)\n{\n    int out_part_len;\n    int limit = INT_MAX / 2 + 1;\n    long out_len = 0;\n\n    do {\n        int in_part_len = in_len > limit ? limit : (int)in_len;\n\n        if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,\n                              &out_part_len, in, in_part_len))\n            return 0;\n\n        out_len += out_part_len;\n        in += in_part_len;\n    } while ((in_len -= limit) > 0);\n\n    if (out_len_ptr)\n        *out_len_ptr = out_len;\n\n    return 1;\n}\n\n/*\n *  call-seq:\n *     cipher.update(data [, buffer]) -> string or buffer\n *\n *  Encrypts data in a streaming fashion. Hand consecutive blocks of data\n *  to the #update method in order to encrypt it. Returns the encrypted\n *  data chunk. When done, the output of Cipher#final should be additionally\n *  added to the result.\n *\n *  If _buffer_ is given, the encryption/decryption result will be written to\n *  it. _buffer_ will be resized automatically.\n *\n *  *NOTE*: When decrypting using an AEAD cipher, the integrity of the output\n *  is not verified until #final has been called.\n */\nstatic VALUE\nossl_cipher_update(int argc, VALUE *argv, VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n    unsigned char *in;\n    long in_len, out_len;\n    VALUE data, str;\n\n    rb_scan_args(argc, argv, \"11\", &data, &str);\n\n    if (!RTEST(rb_attr_get(self, id_key_set)))\n        ossl_raise(eCipherError, \"key not set\");\n\n    StringValue(data);\n    in = (unsigned char *)RSTRING_PTR(data);\n    in_len = RSTRING_LEN(data);\n    GetCipher(self, ctx);\n\n    /*\n     * As of OpenSSL 3.2, there is no reliable way to determine the required\n     * output buffer size for arbitrary cipher modes.\n     * https://github.com/openssl/openssl/issues/22628\n     *\n     * in_len+block_size is usually sufficient, but AES key wrap with padding\n     * ciphers require in_len+15 even though they have a block size of 8 bytes.\n     *\n     * Using EVP_MAX_BLOCK_LENGTH (32) as a safe upper bound for ciphers\n     * currently implemented in OpenSSL, but this can change in the future.\n     */\n    if (in_len > LONG_MAX - EVP_MAX_BLOCK_LENGTH) {\n        ossl_raise(rb_eRangeError,\n                   \"data too big to make output buffer: %ld bytes\", in_len);\n    }\n    out_len = in_len + EVP_MAX_BLOCK_LENGTH;\n\n    if (NIL_P(str))\n        str = rb_str_buf_new(out_len);\n    else {\n        StringValue(str);\n        if ((long)rb_str_capacity(str) >= out_len)\n            rb_str_modify(str);\n        else\n            rb_str_modify_expand(str, out_len - RSTRING_LEN(str));\n    }\n\n    if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str),\n                                 &out_len, in, in_len))\n        ossl_raise(eCipherError, \"EVP_CipherUpdate\");\n    rb_str_set_len(str, out_len);\n\n    return str;\n}\n\n/*\n *  call-seq:\n *     cipher.final -> string\n *\n *  Returns the remaining data held in the cipher object. Further calls to\n *  Cipher#update or Cipher#final are invalid. This call should always\n *  be made as the last call of an encryption or decryption operation, after\n *  having fed the entire plaintext or ciphertext to the Cipher instance.\n *\n *  When encrypting using an AEAD cipher, the authentication tag can be\n *  retrieved by #auth_tag after #final has been called.\n *\n *  When decrypting using an AEAD cipher, this method will verify the integrity\n *  of the ciphertext and the associated data with the authentication tag,\n *  which must be set by #auth_tag= prior to calling this method.\n *  If the verification fails, CipherError will be raised.\n */\nstatic VALUE\nossl_cipher_final(VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n    int out_len;\n    VALUE str;\n\n    GetCipher(self, ctx);\n    str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));\n    if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len)) {\n        /* For AEAD ciphers, this is likely an authentication failure */\n        if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) {\n            /* For AEAD ciphers, EVP_CipherFinal_ex failures are authentication tag verification failures */\n            ossl_raise(eAuthTagError, \"AEAD authentication tag verification failed\");\n        }\n        else {\n            /* For non-AEAD ciphers */\n            ossl_raise(eCipherError, \"cipher final failed\");\n        }\n    }\n    rb_str_set_len(str, out_len);\n\n    return str;\n}\n\n/*\n *  call-seq:\n *     cipher.name -> string\n *\n *  Returns the short name of the cipher which may differ slightly from the\n *  original name provided.\n */\nstatic VALUE\nossl_cipher_name(VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n\n    return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx)));\n}\n\n/*\n *  call-seq:\n *     cipher.key = string\n *\n *  Sets the cipher key. To generate a key, you should either use a secure\n *  random byte string or, if the key is to be derived from a password, you\n *  should rely on PBKDF2 functionality provided by OpenSSL::PKCS5. To\n *  generate a secure random-based key, Cipher#random_key may be used.\n *\n *  Only call this method after calling Cipher#encrypt or Cipher#decrypt.\n *\n *  See also the man page EVP_CipherInit_ex(3).\n */\nstatic VALUE\nossl_cipher_set_key(VALUE self, VALUE key)\n{\n    EVP_CIPHER_CTX *ctx;\n    int key_len;\n\n    StringValue(key);\n    GetCipher(self, ctx);\n\n    key_len = EVP_CIPHER_CTX_key_length(ctx);\n    if (RSTRING_LEN(key) != key_len)\n        ossl_raise(rb_eArgError, \"key must be %d bytes\", key_len);\n\n    if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)\n        ossl_raise(eCipherError, NULL);\n\n    rb_ivar_set(self, id_key_set, Qtrue);\n\n    return key;\n}\n\n/*\n *  call-seq:\n *     cipher.iv = string\n *\n *  Sets the cipher IV. Please note that since you should never be using ECB\n *  mode, an IV is always explicitly required and should be set prior to\n *  encryption. The IV itself can be safely transmitted in public.\n *\n *  This method expects the String to have the length equal to #iv_len. To use\n *  a different IV length with an AEAD cipher, #iv_len= must be set prior to\n *  calling this method.\n *\n *  *NOTE*: In OpenSSL API conventions, the IV value may correspond to the\n *  \"nonce\" instead in some cipher modes. Refer to the OpenSSL man pages for\n *  details.\n *\n *  See also the man page EVP_CipherInit_ex(3).\n */\nstatic VALUE\nossl_cipher_set_iv(VALUE self, VALUE iv)\n{\n    EVP_CIPHER_CTX *ctx;\n    int iv_len = 0;\n\n    StringValue(iv);\n    GetCipher(self, ctx);\n\n    if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)\n        iv_len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);\n    if (!iv_len)\n        iv_len = EVP_CIPHER_CTX_iv_length(ctx);\n    if (RSTRING_LEN(iv) != iv_len)\n        ossl_raise(rb_eArgError, \"iv must be %d bytes\", iv_len);\n\n    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)\n        ossl_raise(eCipherError, NULL);\n\n    return iv;\n}\n\n/*\n *  call-seq:\n *     cipher.authenticated? -> true | false\n *\n *  Indicates whether this Cipher instance uses an AEAD mode.\n */\nstatic VALUE\nossl_cipher_is_authenticated(VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n\n    return (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;\n}\n\n/*\n *  call-seq:\n *     cipher.auth_data = string\n *\n *  Sets additional authenticated data (AAD), also called associated data, for\n *  this Cipher. This method is available for AEAD ciphers.\n *\n *  The contents of this field should be non-sensitive data which will be\n *  added to the ciphertext to generate the authentication tag which validates\n *  the contents of the ciphertext.\n *\n *  This method must be called after #key= and #iv= have been set, but before\n *  starting actual encryption or decryption with #update. In some cipher modes,\n *  #auth_tag_len= and #ccm_data_len= may also need to be called before this\n *  method.\n *\n *  See also the \"AEAD Interface\" section of the man page EVP_EncryptInit(3).\n *  This method internally calls EVP_CipherUpdate() with the output buffer\n *  set to NULL.\n */\nstatic VALUE\nossl_cipher_set_auth_data(VALUE self, VALUE data)\n{\n    EVP_CIPHER_CTX *ctx;\n    unsigned char *in;\n    long in_len, out_len;\n\n    StringValue(data);\n\n    in = (unsigned char *) RSTRING_PTR(data);\n    in_len = RSTRING_LEN(data);\n\n    GetCipher(self, ctx);\n    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))\n        ossl_raise(eCipherError, \"AEAD not supported by this cipher\");\n\n    if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))\n        ossl_raise(eCipherError, \"couldn't set additional authenticated data\");\n\n    return data;\n}\n\n/*\n *  call-seq:\n *     cipher.auth_tag(tag_len = 16) -> String\n *\n *  Gets the generated authentication tag. This method is available for AEAD\n *  ciphers, and should be called after encryption has been finalized by calling\n *  #final.\n *\n *  The returned tag will be _tag_len_ bytes long. Some cipher modes require\n *  the desired length in advance using a separate call to #auth_tag_len=,\n *  before starting encryption.\n *\n *  See also the \"AEAD Interface\" section of the man page EVP_EncryptInit(3).\n *  This method internally calls EVP_CIPHER_CTX_ctrl() with\n *  EVP_CTRL_AEAD_GET_TAG.\n */\nstatic VALUE\nossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)\n{\n    VALUE vtag_len, ret;\n    EVP_CIPHER_CTX *ctx;\n    int tag_len = 16;\n\n    rb_scan_args(argc, argv, \"01\", &vtag_len);\n    if (NIL_P(vtag_len))\n        vtag_len = rb_attr_get(self, id_auth_tag_len);\n    if (!NIL_P(vtag_len))\n        tag_len = NUM2INT(vtag_len);\n\n    GetCipher(self, ctx);\n\n    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))\n        ossl_raise(eCipherError, \"authentication tag not supported by this cipher\");\n\n    ret = rb_str_new(NULL, tag_len);\n    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, RSTRING_PTR(ret)))\n        ossl_raise(eCipherError, \"retrieving the authentication tag failed\");\n\n    return ret;\n}\n\n/*\n *  call-seq:\n *     cipher.auth_tag = string\n *\n *  Sets the authentication tag to verify the integrity of the ciphertext.\n *\n *  The authentication tag must be set before #final is called. The tag is\n *  verified during the #final call.\n *\n *  Note that, for CCM mode and OCB mode, the expected length of the tag must\n *  be set before starting decryption by a separate call to #auth_tag_len=.\n *  The content of the tag can be provided at any time before #final is called.\n *\n *  *NOTE*: The caller must ensure that the String passed to this method has\n *  the desired length. Some cipher modes support variable tag lengths, and\n *  this method may accept a truncated tag without raising an exception.\n *\n *  See also the \"AEAD Interface\" section of the man page EVP_EncryptInit(3).\n *  This method internally calls EVP_CIPHER_CTX_ctrl() with\n *  EVP_CTRL_AEAD_SET_TAG.\n */\nstatic VALUE\nossl_cipher_set_auth_tag(VALUE self, VALUE vtag)\n{\n    EVP_CIPHER_CTX *ctx;\n    unsigned char *tag;\n    int tag_len;\n\n    StringValue(vtag);\n    tag = (unsigned char *) RSTRING_PTR(vtag);\n    tag_len = RSTRING_LENINT(vtag);\n\n    GetCipher(self, ctx);\n    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))\n        ossl_raise(eCipherError, \"authentication tag not supported by this cipher\");\n\n    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, tag))\n        ossl_raise(eCipherError, \"unable to set AEAD tag\");\n\n    return vtag;\n}\n\n/*\n *  call-seq:\n *     cipher.auth_tag_len = integer\n *\n *  Sets the length of the expected authentication tag for this Cipher. This\n *  method is available for some of AEAD ciphers that require the length to be\n *  set before starting encryption or decryption, such as CCM mode or OCB mode.\n *\n *  For CCM mode and OCB mode, the tag length must be set before #iv= is set.\n *\n *  See also the \"AEAD Interface\" section of the man page EVP_EncryptInit(3).\n *  This method internally calls EVP_CIPHER_CTX_ctrl() with\n *  EVP_CTRL_AEAD_SET_TAG and a NULL buffer.\n */\nstatic VALUE\nossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)\n{\n    int tag_len = NUM2INT(vlen);\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))\n        ossl_raise(eCipherError, \"AEAD not supported by this cipher\");\n\n    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))\n        ossl_raise(eCipherError, \"unable to set authentication tag length\");\n\n    /* for #auth_tag */\n    rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len));\n\n    return vlen;\n}\n\n/*\n * call-seq:\n *    cipher.iv_len = integer\n *\n * Sets the IV/nonce length for this Cipher. This method is available for AEAD\n * ciphers that support variable IV lengths. This method can be called if a\n * different IV length than OpenSSL's default is desired, prior to calling\n * #iv=.\n *\n * See also the \"AEAD Interface\" section of the man page EVP_EncryptInit(3).\n * This method internally calls EVP_CIPHER_CTX_ctrl() with\n * EVP_CTRL_AEAD_SET_IVLEN.\n */\nstatic VALUE\nossl_cipher_set_iv_length(VALUE self, VALUE iv_length)\n{\n    int len = NUM2INT(iv_length);\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n    if (!(EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER))\n        ossl_raise(eCipherError, \"cipher does not support AEAD\");\n\n    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, len, NULL))\n        ossl_raise(eCipherError, \"unable to set IV length\");\n\n    /*\n     * EVP_CIPHER_CTX_iv_length() returns the default length. So we need to save\n     * the length somewhere. Luckily currently we aren't using app_data.\n     */\n    EVP_CIPHER_CTX_set_app_data(ctx, (void *)(VALUE)len);\n\n    return iv_length;\n}\n\n/*\n *  call-seq:\n *     cipher.key_len = integer\n *\n *  Sets the key length of the cipher.  If the cipher is a fixed length cipher\n *  then attempting to set the key length to any value other than the fixed\n *  value is an error.\n *\n *  Under normal circumstances you do not need to call this method (and\n *  probably shouldn't).\n *\n *  See EVP_CIPHER_CTX_set_key_length for further information.\n */\nstatic VALUE\nossl_cipher_set_key_length(VALUE self, VALUE key_length)\n{\n    int len = NUM2INT(key_length);\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n    if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1)\n        ossl_raise(eCipherError, NULL);\n\n    return key_length;\n}\n\n// TODO: Should #padding= take a boolean value instead?\n/*\n *  call-seq:\n *     cipher.padding = 1 or 0\n *\n *  Enables or disables padding. By default encryption operations are padded\n *  using standard block padding and the padding is checked and removed when\n *  decrypting. If the pad parameter is zero then no padding is performed, the\n *  total amount of data encrypted or decrypted must then be a multiple of the\n *  block size or an error will occur.\n *\n *  See EVP_CIPHER_CTX_set_padding for further information.\n */\nstatic VALUE\nossl_cipher_set_padding(VALUE self, VALUE padding)\n{\n    EVP_CIPHER_CTX *ctx;\n    int pad = NUM2INT(padding);\n\n    GetCipher(self, ctx);\n    if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)\n        ossl_raise(eCipherError, NULL);\n    return padding;\n}\n\n/*\n *  call-seq:\n *     cipher.key_len -> integer\n *\n *  Returns the key length in bytes of the Cipher.\n */\nstatic VALUE\nossl_cipher_key_length(VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n\n    return INT2NUM(EVP_CIPHER_CTX_key_length(ctx));\n}\n\n/*\n *  call-seq:\n *     cipher.iv_len -> integer\n *\n *  Returns the expected length in bytes for an IV for this Cipher.\n */\nstatic VALUE\nossl_cipher_iv_length(VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n    int len = 0;\n\n    GetCipher(self, ctx);\n    if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_AEAD_CIPHER)\n        len = (int)(VALUE)EVP_CIPHER_CTX_get_app_data(ctx);\n    if (!len)\n        len = EVP_CIPHER_CTX_iv_length(ctx);\n\n    return INT2NUM(len);\n}\n\n/*\n *  call-seq:\n *     cipher.block_size -> integer\n *\n *  Returns the size in bytes of the blocks on which this Cipher operates on.\n */\nstatic VALUE\nossl_cipher_block_size(VALUE self)\n{\n    EVP_CIPHER_CTX *ctx;\n\n    GetCipher(self, ctx);\n\n    return INT2NUM(EVP_CIPHER_CTX_block_size(ctx));\n}\n\n/*\n *  call-seq:\n *     cipher.ccm_data_len = integer\n *\n *  Sets the total length of the plaintext / ciphertext message that will be\n *  processed by #update in CCM mode.\n *\n *  Make sure to call this method after #key= and #iv= have been set, and\n *  before #auth_data= or #update are called.\n *\n *  This method is only available for CCM mode ciphers.\n *\n *  See also the \"AEAD Interface\" section of the man page EVP_EncryptInit(3).\n */\nstatic VALUE\nossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)\n{\n    int in_len, out_len;\n    EVP_CIPHER_CTX *ctx;\n\n    in_len = NUM2INT(data_len);\n\n    GetCipher(self, ctx);\n    if (EVP_CipherUpdate(ctx, NULL, &out_len, NULL, in_len) != 1)\n        ossl_raise(eCipherError, NULL);\n\n    return data_len;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_cipher(void)\n{\n    /* Document-class: OpenSSL::Cipher\n     *\n     * Provides symmetric algorithms for encryption and decryption. The\n     * algorithms that are available depend on the particular version\n     * of OpenSSL that is installed.\n     *\n     * === Listing all supported algorithms\n     *\n     * A list of supported algorithms can be obtained by\n     *\n     *   puts OpenSSL::Cipher.ciphers\n     *\n     * === Instantiating a Cipher\n     *\n     * There are several ways to create a Cipher instance. Generally, a\n     * Cipher algorithm is categorized by its name, the key length in bits\n     * and the cipher mode to be used. The most generic way to create a\n     * Cipher is the following\n     *\n     *   cipher = OpenSSL::Cipher.new('<name>-<key length>-<mode>')\n     *\n     * That is, a string consisting of the hyphenated concatenation of the\n     * individual components name, key length and mode. Either all uppercase\n     * or all lowercase strings may be used, for example:\n     *\n     *  cipher = OpenSSL::Cipher.new('aes-128-cbc')\n     *\n     * === Choosing either encryption or decryption mode\n     *\n     * Encryption and decryption are often very similar operations for\n     * symmetric algorithms, this is reflected by not having to choose\n     * different classes for either operation, both can be done using the\n     * same class. Still, after obtaining a Cipher instance, we need to\n     * tell the instance what it is that we intend to do with it, so we\n     * need to call either\n     *\n     *   cipher.encrypt\n     *\n     * or\n     *\n     *   cipher.decrypt\n     *\n     * on the Cipher instance. This should be the first call after creating\n     * the instance, otherwise configuration that has already been set could\n     * get lost in the process.\n     *\n     * === Choosing a key\n     *\n     * Symmetric encryption requires a key that is the same for the encrypting\n     * and for the decrypting party and after initial key establishment should\n     * be kept as private information. There are a lot of ways to create\n     * insecure keys, the most notable is to simply take a password as the key\n     * without processing the password further. A simple and secure way to\n     * create a key for a particular Cipher is\n     *\n     *  cipher = OpenSSL::Cipher.new('aes-256-cfb')\n     *  cipher.encrypt\n     *  key = cipher.random_key # also sets the generated key on the Cipher\n     *\n     * If you absolutely need to use passwords as encryption keys, you\n     * should use Password-Based Key Derivation Function 2 (PBKDF2) by\n     * generating the key with the help of the functionality provided by\n     * OpenSSL::PKCS5.pbkdf2_hmac_sha1 or OpenSSL::PKCS5.pbkdf2_hmac.\n     *\n     * Although there is Cipher#pkcs5_keyivgen, its use is deprecated and\n     * it should only be used in legacy applications because it does not use\n     * the newer PKCS#5 v2 algorithms.\n     *\n     * === Choosing an IV\n     *\n     * The cipher modes CBC, CFB, OFB and CTR all need an \"initialization\n     * vector\", or short, IV. ECB mode is the only mode that does not require\n     * an IV, but there is almost no legitimate use case for this mode\n     * because of the fact that it does not sufficiently hide plaintext\n     * patterns. Therefore\n     *\n     * <b>You should never use ECB mode unless you are absolutely sure that\n     * you absolutely need it</b>\n     *\n     * Because of this, you will end up with a mode that explicitly requires\n     * an IV in any case. Although the IV can be seen as public information,\n     * i.e. it may be transmitted in public once generated, it should still\n     * stay unpredictable to prevent certain kinds of attacks. Therefore,\n     * ideally\n     *\n     * <b>Always create a secure random IV for every encryption of your\n     * Cipher</b>\n     *\n     * A new, random IV should be created for every encryption of data. Think\n     * of the IV as a nonce (number used once) - it's public but random and\n     * unpredictable. A secure random IV can be created as follows\n     *\n     *   cipher = ...\n     *   cipher.encrypt\n     *   key = cipher.random_key\n     *   iv = cipher.random_iv # also sets the generated IV on the Cipher\n     *\n     * Although the key is generally a random value, too, it is a bad choice\n     * as an IV. There are elaborate ways how an attacker can take advantage\n     * of such an IV. As a general rule of thumb, exposing the key directly\n     * or indirectly should be avoided at all cost and exceptions only be\n     * made with good reason.\n     *\n     * === Calling Cipher#final\n     *\n     * ECB (which should not be used) and CBC are both block-based modes.\n     * This means that unlike for the other streaming-based modes, they\n     * operate on fixed-size blocks of data, and therefore they require a\n     * \"finalization\" step to produce or correctly decrypt the last block of\n     * data by appropriately handling some form of padding. Therefore it is\n     * essential to add the output of OpenSSL::Cipher#final to your\n     * encryption/decryption buffer or you will end up with decryption errors\n     * or truncated data.\n     *\n     * Although this is not really necessary for streaming-mode ciphers, it is\n     * still recommended to apply the same pattern of adding the output of\n     * Cipher#final there as well - it also enables you to switch between\n     * modes more easily in the future.\n     *\n     * === Encrypting and decrypting some data\n     *\n     *   data = \"Very, very confidential data\"\n     *\n     *   cipher = OpenSSL::Cipher.new('aes-128-cbc')\n     *   cipher.encrypt\n     *   key = cipher.random_key\n     *   iv = cipher.random_iv\n     *\n     *   encrypted = cipher.update(data) + cipher.final\n     *   ...\n     *   decipher = OpenSSL::Cipher.new('aes-128-cbc')\n     *   decipher.decrypt\n     *   decipher.key = key\n     *   decipher.iv = iv\n     *\n     *   plain = decipher.update(encrypted) + decipher.final\n     *\n     *   puts data == plain #=> true\n     *\n     * === Authenticated Encryption and Associated Data (AEAD)\n     *\n     * If the OpenSSL version used supports it, an Authenticated Encryption\n     * mode (such as GCM or CCM) should always be preferred over any\n     * unauthenticated mode. Currently, OpenSSL supports AE only in combination\n     * with Associated Data (AEAD) where additional associated data is included\n     * in the encryption process to compute a tag at the end of the encryption.\n     * This tag will also be used in the decryption process and by verifying\n     * its validity, the authenticity of a given ciphertext is established.\n     *\n     * This is superior to unauthenticated modes in that it allows to detect\n     * if somebody effectively changed the ciphertext after it had been\n     * encrypted. This prevents malicious modifications of the ciphertext that\n     * could otherwise be exploited to modify ciphertexts in ways beneficial to\n     * potential attackers.\n     *\n     * Associated data, also called additional authenticated data (AAD), is\n     * optionally used where there is additional information, such as\n     * headers or some metadata, that must be also authenticated but not\n     * necessarily need to be encrypted.\n     *\n     * An example using the GCM (Galois/Counter Mode). You have 16 bytes _key_,\n     * 12 bytes (96 bits) _nonce_ and the associated data _auth_data_. Be sure\n     * not to reuse the _key_ and _nonce_ pair. Reusing an nonce ruins the\n     * security guarantees of GCM mode.\n     *\n     *   key = OpenSSL::Random.random_bytes(16)\n     *   nonce = OpenSSL::Random.random_bytes(12)\n     *   auth_data = \"authenticated but unencrypted data\"\n     *   data = \"encrypted data\"\n     *\n     *   cipher = OpenSSL::Cipher.new('aes-128-gcm').encrypt\n     *   cipher.key = key\n     *   cipher.iv = nonce\n     *   cipher.auth_data = auth_data\n     *\n     *   encrypted = cipher.update(data) + cipher.final\n     *   tag = cipher.auth_tag(16)\n     *\n     * Now you are the receiver. You know the _key_ and have received _nonce_,\n     * _auth_data_, _encrypted_ and _tag_ through an untrusted network. Note\n     * that GCM accepts an arbitrary length tag between 1 and 16 bytes. You may\n     * additionally need to check that the received tag has the correct length,\n     * or you allow attackers to forge a valid single byte tag for the tampered\n     * ciphertext with a probability of 1/256.\n     *\n     *   raise \"tag is truncated!\" unless tag.bytesize == 16\n     *   decipher = OpenSSL::Cipher.new('aes-128-gcm').decrypt\n     *   decipher.key = key\n     *   decipher.iv = nonce\n     *   decipher.auth_tag = tag # could be called at any time before #final\n     *   decipher.auth_data = auth_data\n     *\n     *   decrypted = decipher.update(encrypted) + decipher.final\n     *\n     *   puts data == decrypted #=> true\n     *\n     * Note that other AEAD ciphers may require additional steps, such as\n     * setting the expected tag length (#auth_tag_len=) or the total data\n     * length (#ccm_data_len=) in advance. Make sure to read the relevant man\n     * page for details.\n     */\n    cCipher = rb_define_class_under(mOSSL, \"Cipher\", rb_cObject);\n    eCipherError = rb_define_class_under(cCipher, \"CipherError\", eOSSLError);\n    eAuthTagError = rb_define_class_under(cCipher, \"AuthTagError\", eCipherError);\n\n    rb_define_alloc_func(cCipher, ossl_cipher_alloc);\n    rb_define_method(cCipher, \"initialize_copy\", ossl_cipher_copy, 1);\n    rb_define_module_function(cCipher, \"ciphers\", ossl_s_ciphers, 0);\n    rb_define_method(cCipher, \"initialize\", ossl_cipher_initialize, 1);\n    rb_define_method(cCipher, \"reset\", ossl_cipher_reset, 0);\n    rb_define_method(cCipher, \"encrypt\", ossl_cipher_encrypt, 0);\n    rb_define_method(cCipher, \"decrypt\", ossl_cipher_decrypt, 0);\n    rb_define_method(cCipher, \"pkcs5_keyivgen\", ossl_cipher_pkcs5_keyivgen, -1);\n    rb_define_method(cCipher, \"update\", ossl_cipher_update, -1);\n    rb_define_method(cCipher, \"final\", ossl_cipher_final, 0);\n    rb_define_method(cCipher, \"name\", ossl_cipher_name, 0);\n    rb_define_method(cCipher, \"key=\", ossl_cipher_set_key, 1);\n    rb_define_method(cCipher, \"auth_data=\", ossl_cipher_set_auth_data, 1);\n    rb_define_method(cCipher, \"auth_tag=\", ossl_cipher_set_auth_tag, 1);\n    rb_define_method(cCipher, \"auth_tag\", ossl_cipher_get_auth_tag, -1);\n    rb_define_method(cCipher, \"auth_tag_len=\", ossl_cipher_set_auth_tag_len, 1);\n    rb_define_method(cCipher, \"authenticated?\", ossl_cipher_is_authenticated, 0);\n    rb_define_method(cCipher, \"key_len=\", ossl_cipher_set_key_length, 1);\n    rb_define_method(cCipher, \"key_len\", ossl_cipher_key_length, 0);\n    rb_define_method(cCipher, \"iv=\", ossl_cipher_set_iv, 1);\n    rb_define_method(cCipher, \"iv_len=\", ossl_cipher_set_iv_length, 1);\n    rb_define_method(cCipher, \"iv_len\", ossl_cipher_iv_length, 0);\n    rb_define_method(cCipher, \"block_size\", ossl_cipher_block_size, 0);\n    rb_define_method(cCipher, \"padding=\", ossl_cipher_set_padding, 1);\n    rb_define_method(cCipher, \"ccm_data_len=\", ossl_cipher_set_ccm_data_len, 1);\n\n    id_auth_tag_len = rb_intern_const(\"auth_tag_len\");\n    id_key_set = rb_intern_const(\"key_set\");\n    id_cipher_holder = rb_intern_const(\"EVP_CIPHER_holder\");\n}\n"
  },
  {
    "path": "ext/openssl/ossl_cipher.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_CIPHER_H_)\n#define _OSSL_CIPHER_H_\n\n/*\n * Gets EVP_CIPHER from a String or an OpenSSL::Digest instance (discouraged,\n * but still supported for compatibility). A holder object is created if the\n * EVP_CIPHER is a \"fetched\" algorithm.\n */\nconst EVP_CIPHER *ossl_evp_cipher_fetch(VALUE obj, volatile VALUE *holder);\n/*\n * This is meant for OpenSSL::Engine#cipher. EVP_CIPHER must not be a fetched\n * one.\n */\nVALUE ossl_cipher_new(const EVP_CIPHER *);\nvoid Init_ossl_cipher(void);\n\n#endif /* _OSSL_CIPHER_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_config.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\nstatic VALUE cConfig, eConfigError;\n\nstatic void\nnconf_free(void *conf)\n{\n    NCONF_free(conf);\n}\n\nstatic const rb_data_type_t ossl_config_type = {\n    \"OpenSSL/CONF\",\n    {\n        0, nconf_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,\n};\n\nCONF *\nGetConfig(VALUE obj)\n{\n    CONF *conf;\n\n    TypedData_Get_Struct(obj, CONF, &ossl_config_type, conf);\n    if (!conf)\n        rb_raise(rb_eRuntimeError, \"CONF is not initialized\");\n    return conf;\n}\n\nstatic VALUE\nconfig_s_alloc(VALUE klass)\n{\n    VALUE obj;\n    CONF *conf;\n\n    obj = TypedData_Wrap_Struct(klass, &ossl_config_type, 0);\n    conf = NCONF_new(NULL);\n    if (!conf)\n        ossl_raise(eConfigError, \"NCONF_new\");\n    RTYPEDDATA_DATA(obj) = conf;\n    return obj;\n}\n\nstatic void\nconfig_load_bio(CONF *conf, BIO *bio)\n{\n    long eline = -1;\n\n    if (!NCONF_load_bio(conf, bio, &eline)) {\n        BIO_free(bio);\n        if (eline <= 0)\n            ossl_raise(eConfigError, \"wrong config format\");\n        else\n            ossl_raise(eConfigError, \"error in line %ld\", eline);\n    }\n    BIO_free(bio);\n\n    /*\n     * Clear the error queue even if it is parsed successfully.\n     * Particularly, when the .include directive refers to a non-existent file,\n     * it is only reported in the error queue.\n     */\n    ossl_clear_error();\n}\n\n/*\n * call-seq:\n *    Config.parse(string) -> OpenSSL::Config\n *\n * Parses a given _string_ as a blob that contains configuration for OpenSSL.\n */\nstatic VALUE\nconfig_s_parse(VALUE klass, VALUE str)\n{\n    VALUE obj = config_s_alloc(klass);\n    CONF *conf = GetConfig(obj);\n    BIO *bio;\n\n    bio = ossl_obj2bio(&str);\n    config_load_bio(conf, bio); /* Consumes BIO */\n    rb_obj_freeze(obj);\n    return obj;\n}\n\nstatic VALUE config_get_sections(VALUE self);\nstatic VALUE config_get_section(VALUE self, VALUE section);\n\n/*\n * call-seq:\n *    Config.parse_config(io) -> hash\n *\n * Parses the configuration data read from _io_ and returns the whole content\n * as a Hash.\n */\nstatic VALUE\nconfig_s_parse_config(VALUE klass, VALUE io)\n{\n    VALUE obj, sections, ret;\n    long i;\n\n    obj = config_s_parse(klass, io);\n    sections = config_get_sections(obj);\n    ret = rb_hash_new();\n    for (i = 0; i < RARRAY_LEN(sections); i++) {\n        VALUE section = rb_ary_entry(sections, i);\n        rb_hash_aset(ret, section, config_get_section(obj, section));\n    }\n    return ret;\n}\n\n/*\n * call-seq:\n *    Config.new(filename) -> OpenSSL::Config\n *\n * Creates an instance of OpenSSL::Config from the content of the file\n * specified by _filename_.\n *\n * This can be used in contexts like OpenSSL::X509::ExtensionFactory.config=\n *\n * This can raise IO exceptions based on the access, or availability of the\n * file. A ConfigError exception may be raised depending on the validity of\n * the data being configured.\n */\nstatic VALUE\nconfig_initialize(int argc, VALUE *argv, VALUE self)\n{\n    CONF *conf = GetConfig(self);\n    VALUE filename;\n\n    /* 0-arguments call has no use-case, but is kept for compatibility */\n    rb_scan_args(argc, argv, \"01\", &filename);\n    rb_check_frozen(self);\n    if (!NIL_P(filename)) {\n        BIO *bio = BIO_new_file(StringValueCStr(filename), \"rb\");\n        if (!bio)\n            ossl_raise(eConfigError, \"BIO_new_file\");\n        config_load_bio(conf, bio); /* Consumes BIO */\n    }\n    rb_obj_freeze(self);\n    return self;\n}\n\nstatic VALUE\nconfig_initialize_copy(VALUE self, VALUE other)\n{\n    CONF *conf = GetConfig(self);\n    VALUE str;\n    BIO *bio;\n\n    str = rb_funcall(other, rb_intern(\"to_s\"), 0);\n    rb_check_frozen(self);\n    bio = ossl_obj2bio(&str);\n    config_load_bio(conf, bio); /* Consumes BIO */\n    rb_obj_freeze(self);\n    return self;\n}\n\n/*\n * call-seq:\n *    config.get_value(section, key) -> string\n *\n * Gets the value of _key_ from the given _section_.\n *\n * Given the following configurating file being loaded:\n *\n *   config = OpenSSL::Config.load('foo.cnf')\n *     #=> #<OpenSSL::Config sections=[\"default\"]>\n *   puts config.to_s\n *     #=> [ default ]\n *     #   foo=bar\n *\n * You can get a specific value from the config if you know the _section_\n * and _key_ like so:\n *\n *   config.get_value('default','foo')\n *     #=> \"bar\"\n */\nstatic VALUE\nconfig_get_value(VALUE self, VALUE section, VALUE key)\n{\n    CONF *conf = GetConfig(self);\n    const char *str, *sectionp;\n\n    StringValueCStr(section);\n    StringValueCStr(key);\n    /* For compatibility; NULL means \"default\". */\n    sectionp = RSTRING_LEN(section) ? RSTRING_PTR(section) : NULL;\n    str = NCONF_get_string(conf, sectionp, RSTRING_PTR(key));\n    if (!str) {\n        ossl_clear_error();\n        return Qnil;\n    }\n    return rb_str_new_cstr(str);\n}\n\n/*\n * call-seq:\n *    config[section] -> hash\n *\n * Gets all key-value pairs in a specific _section_ from the current\n * configuration.\n *\n * Given the following configurating file being loaded:\n *\n *   config = OpenSSL::Config.load('foo.cnf')\n *     #=> #<OpenSSL::Config sections=[\"default\"]>\n *   puts config.to_s\n *     #=> [ default ]\n *     #   foo=bar\n *\n * You can get a hash of the specific section like so:\n *\n *   config['default']\n *     #=> {\"foo\"=>\"bar\"}\n *\n */\nstatic VALUE\nconfig_get_section(VALUE self, VALUE section)\n{\n    CONF *conf = GetConfig(self);\n    STACK_OF(CONF_VALUE) *sk;\n    int i, entries;\n    VALUE hash;\n\n    hash = rb_hash_new();\n    StringValueCStr(section);\n    if (!(sk = NCONF_get_section(conf, RSTRING_PTR(section)))) {\n        ossl_clear_error();\n        return hash;\n    }\n    entries = sk_CONF_VALUE_num(sk);\n    for (i = 0; i < entries; i++) {\n        CONF_VALUE *entry = sk_CONF_VALUE_value(sk, i);\n        rb_hash_aset(hash, rb_str_new_cstr(entry->name),\n                     rb_str_new_cstr(entry->value));\n    }\n    return hash;\n}\n\nstatic void\nget_conf_section_doall_arg(CONF_VALUE *cv, VALUE *aryp)\n{\n    if (cv->name)\n        return;\n    rb_ary_push(*aryp, rb_str_new_cstr(cv->section));\n}\n\n/* IMPLEMENT_LHASH_DOALL_ARG_CONST() requires >= OpenSSL 1.1.0 */\nstatic IMPLEMENT_LHASH_DOALL_ARG_FN(get_conf_section, CONF_VALUE, VALUE)\n\n/*\n * call-seq:\n *    config.sections -> array of string\n *\n * Get the names of all sections in the current configuration.\n */\nstatic VALUE\nconfig_get_sections(VALUE self)\n{\n    CONF *conf = GetConfig(self);\n    VALUE ary;\n\n    ary = rb_ary_new();\n    lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(get_conf_section),\n                 &ary);\n    return ary;\n}\n\nstatic void\ndump_conf_value_doall_arg(CONF_VALUE *cv, VALUE *strp)\n{\n    VALUE str = *strp;\n    STACK_OF(CONF_VALUE) *sk;\n    int i, num;\n\n    if (cv->name)\n        return;\n    sk = (STACK_OF(CONF_VALUE) *)cv->value;\n    num = sk_CONF_VALUE_num(sk);\n    rb_str_cat_cstr(str, \"[ \");\n    rb_str_cat_cstr(str, cv->section);\n    rb_str_cat_cstr(str, \" ]\\n\");\n    for (i = 0; i < num; i++){\n        CONF_VALUE *v = sk_CONF_VALUE_value(sk, i);\n        rb_str_cat_cstr(str, v->name ? v->name : \"None\");\n        rb_str_cat_cstr(str, \"=\");\n        rb_str_cat_cstr(str, v->value ? v->value : \"None\");\n        rb_str_cat_cstr(str, \"\\n\");\n    }\n    rb_str_cat_cstr(str, \"\\n\");\n}\n\nstatic IMPLEMENT_LHASH_DOALL_ARG_FN(dump_conf_value, CONF_VALUE, VALUE)\n\n/*\n * call-seq:\n *    config.to_s -> string\n *\n *\n * Gets the parsable form of the current configuration.\n *\n * Given the following configuration file being loaded:\n *\n *   config = OpenSSL::Config.load('baz.cnf')\n *     #=> #<OpenSSL::Config sections=[\"default\"]>\n *   puts config.to_s\n *     #=> [ default ]\n *     #   foo=bar\n *     #   baz=buz\n *\n * You can get the serialized configuration using #to_s and then parse\n * it later:\n *\n *   serialized_config = config.to_s\n *   # much later...\n *   new_config = OpenSSL::Config.parse(serialized_config)\n *     #=> #<OpenSSL::Config sections=[\"default\"]>\n *   puts new_config\n *     #=> [ default ]\n *         foo=bar\n *         baz=buz\n */\nstatic VALUE\nconfig_to_s(VALUE self)\n{\n    CONF *conf = GetConfig(self);\n    VALUE str;\n\n    str = rb_str_new(NULL, 0);\n    lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(dump_conf_value),\n                 &str);\n    return str;\n}\n\nstatic void\neach_conf_value_doall_arg(CONF_VALUE *cv, void *unused)\n{\n    STACK_OF(CONF_VALUE) *sk;\n    VALUE section;\n    int i, num;\n\n    if (cv->name)\n        return;\n    sk = (STACK_OF(CONF_VALUE) *)cv->value;\n    num = sk_CONF_VALUE_num(sk);\n    section = rb_str_new_cstr(cv->section);\n    for (i = 0; i < num; i++){\n        CONF_VALUE *v = sk_CONF_VALUE_value(sk, i);\n        VALUE name = v->name ? rb_str_new_cstr(v->name) : Qnil;\n        VALUE value = v->value ? rb_str_new_cstr(v->value) : Qnil;\n        rb_yield(rb_ary_new3(3, section, name, value));\n    }\n}\n\nstatic IMPLEMENT_LHASH_DOALL_ARG_FN(each_conf_value, CONF_VALUE, void)\n\n/*\n * call-seq:\n *    config.each { |section, key, value| }\n *\n * Retrieves the section and its pairs for the current configuration.\n *\n *    config.each do |section, key, value|\n *      # ...\n *    end\n */\nstatic VALUE\nconfig_each(VALUE self)\n{\n    CONF *conf = GetConfig(self);\n\n    RETURN_ENUMERATOR(self, 0, 0);\n\n    lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(each_conf_value),\n                 NULL);\n    return self;\n}\n\n/*\n * call-seq:\n *    config.inspect -> string\n *\n * String representation of this configuration object, including the class\n * name and its sections.\n */\nstatic VALUE\nconfig_inspect(VALUE self)\n{\n    VALUE str, ary = config_get_sections(self);\n    const char *cname = rb_class2name(rb_obj_class(self));\n\n    str = rb_str_new_cstr(\"#<\");\n    rb_str_cat_cstr(str, cname);\n    rb_str_cat_cstr(str, \" sections=\");\n    rb_str_append(str, rb_inspect(ary));\n    rb_str_cat_cstr(str, \">\");\n\n    return str;\n}\n\nvoid\nInit_ossl_config(void)\n{\n    char *path;\n    VALUE path_str;\n\n    /* Document-class: OpenSSL::Config\n     *\n     * Configuration for the openssl library.\n     *\n     * Many system's installation of openssl library will depend on your system\n     * configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for\n     * the location of the file for your host.\n     *\n     * See also https://docs.openssl.org/master/man5/config/\n     */\n    cConfig = rb_define_class_under(mOSSL, \"Config\", rb_cObject);\n\n    /* Document-class: OpenSSL::ConfigError\n     *\n     * General error for openssl library configuration files. Including formatting,\n     * parsing errors, etc.\n     */\n    eConfigError = rb_define_class_under(mOSSL, \"ConfigError\", eOSSLError);\n\n    rb_include_module(cConfig, rb_mEnumerable);\n    rb_define_singleton_method(cConfig, \"parse\", config_s_parse, 1);\n    rb_define_singleton_method(cConfig, \"parse_config\", config_s_parse_config, 1);\n    rb_define_alias(CLASS_OF(cConfig), \"load\", \"new\");\n    rb_define_alloc_func(cConfig, config_s_alloc);\n    rb_define_method(cConfig, \"initialize\", config_initialize, -1);\n    rb_define_method(cConfig, \"initialize_copy\", config_initialize_copy, 1);\n    rb_define_method(cConfig, \"get_value\", config_get_value, 2);\n    rb_define_method(cConfig, \"[]\", config_get_section, 1);\n    rb_define_method(cConfig, \"sections\", config_get_sections, 0);\n    rb_define_method(cConfig, \"to_s\", config_to_s, 0);\n    rb_define_method(cConfig, \"each\", config_each, 0);\n    rb_define_method(cConfig, \"inspect\", config_inspect, 0);\n\n    /* Document-const: DEFAULT_CONFIG_FILE\n     *\n     * The default system configuration file for OpenSSL.\n     */\n    path = CONF_get1_default_config_file();\n    path_str = rb_obj_freeze(ossl_buf2str(path, rb_long2int(strlen(path))));\n    rb_define_const(cConfig, \"DEFAULT_CONFIG_FILE\", path_str);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_config.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#ifndef OSSL_CONFIG_H\n#define OSSL_CONFIG_H\n\nCONF *GetConfig(VALUE obj);\nvoid Init_ossl_config(void);\n\n#endif /* OSSL_CONFIG_H */\n"
  },
  {
    "path": "ext/openssl/ossl_digest.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define GetDigest(obj, ctx) do { \\\n    TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_digest_type, (ctx)); \\\n    if (!(ctx)) { \\\n        ossl_raise(rb_eRuntimeError, \"Digest CTX wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nstatic VALUE cDigest;\nstatic VALUE eDigestError;\nstatic ID id_md_holder;\n\nstatic VALUE ossl_digest_alloc(VALUE klass);\n\nstatic void\nossl_digest_free(void *ctx)\n{\n    EVP_MD_CTX_destroy(ctx);\n}\n\nstatic const rb_data_type_t ossl_digest_type = {\n    \"OpenSSL/Digest\",\n    {\n        0, ossl_digest_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n#ifdef OSSL_USE_PROVIDER\nstatic void\nossl_evp_md_free(void *ptr)\n{\n    // This is safe to call against const EVP_MD * returned by\n    // EVP_get_digestbyname()\n    EVP_MD_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_evp_md_holder_type = {\n    \"OpenSSL/EVP_MD\",\n    {\n        .dfree = ossl_evp_md_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n#endif\n\n/*\n * Public\n */\nconst EVP_MD *\nossl_evp_md_fetch(VALUE obj, volatile VALUE *holder)\n{\n    *holder = Qnil;\n    if (rb_obj_is_kind_of(obj, cDigest)) {\n        EVP_MD_CTX *ctx;\n        GetDigest(obj, ctx);\n        EVP_MD *md = (EVP_MD *)EVP_MD_CTX_get0_md(ctx);\n#ifdef OSSL_USE_PROVIDER\n        *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);\n        if (!EVP_MD_up_ref(md))\n            ossl_raise(eDigestError, \"EVP_MD_up_ref\");\n        RTYPEDDATA_DATA(*holder) = md;\n#endif\n        return md;\n    }\n\n    const char *name = StringValueCStr(obj);\n    EVP_MD *md = (EVP_MD *)EVP_get_digestbyname(name);\n    if (!md) {\n        ASN1_OBJECT *oid = OBJ_txt2obj(name, 0);\n        md = (EVP_MD *)EVP_get_digestbyobj(oid);\n        ASN1_OBJECT_free(oid);\n    }\n#ifdef OSSL_USE_PROVIDER\n    if (!md) {\n        ossl_clear_error();\n        *holder = TypedData_Wrap_Struct(0, &ossl_evp_md_holder_type, NULL);\n        md = EVP_MD_fetch(NULL, name, NULL);\n        RTYPEDDATA_DATA(*holder) = md;\n    }\n#endif\n    if (!md)\n        ossl_raise(eDigestError, \"unsupported digest algorithm: %\"PRIsVALUE,\n                   obj);\n    return md;\n}\n\nVALUE\nossl_digest_new(const EVP_MD *md)\n{\n    VALUE ret;\n    EVP_MD_CTX *ctx;\n\n    // NOTE: This does not set id_md_holder because this function should\n    // only be called from ossl_engine.c, which will not use any\n    // reference-counted digests.\n    ret = ossl_digest_alloc(cDigest);\n    ctx = EVP_MD_CTX_new();\n    if (!ctx)\n        ossl_raise(eDigestError, \"EVP_MD_CTX_new\");\n    RTYPEDDATA_DATA(ret) = ctx;\n\n    if (!EVP_DigestInit_ex(ctx, md, NULL))\n        ossl_raise(eDigestError, \"Digest initialization failed\");\n\n    return ret;\n}\n\n/*\n * Private\n */\nstatic VALUE\nossl_digest_alloc(VALUE klass)\n{\n    return TypedData_Wrap_Struct(klass, &ossl_digest_type, 0);\n}\n\nstatic VALUE ossl_digest_update(VALUE, VALUE);\n\n/*\n *  call-seq:\n *     Digest.new(string [, data]) -> Digest\n *\n * Creates a Digest instance based on _string_, which is either the ln\n * (long name) or sn (short name) of a supported digest algorithm. A list of\n * supported algorithms can be obtained by calling OpenSSL::Digest.digests.\n *\n * If _data_ (a String) is given, it is used as the initial input to the\n * Digest instance, i.e.\n *\n *   digest = OpenSSL::Digest.new('sha256', 'digestdata')\n *\n * is equivalent to\n *\n *   digest = OpenSSL::Digest.new('sha256')\n *   digest.update('digestdata')\n */\nstatic VALUE\nossl_digest_initialize(int argc, VALUE *argv, VALUE self)\n{\n    EVP_MD_CTX *ctx;\n    const EVP_MD *md;\n    VALUE type, data, md_holder;\n\n    rb_scan_args(argc, argv, \"11\", &type, &data);\n    md = ossl_evp_md_fetch(type, &md_holder);\n    if (!NIL_P(data)) StringValue(data);\n\n    TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx);\n    if (!ctx) {\n        RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();\n        if (!ctx)\n            ossl_raise(eDigestError, \"EVP_MD_CTX_new\");\n    }\n\n    if (!EVP_DigestInit_ex(ctx, md, NULL))\n        ossl_raise(eDigestError, \"Digest initialization failed\");\n    rb_ivar_set(self, id_md_holder, md_holder);\n\n    if (!NIL_P(data)) return ossl_digest_update(self, data);\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_digest_copy(VALUE self, VALUE other)\n{\n    EVP_MD_CTX *ctx1, *ctx2;\n\n    rb_check_frozen(self);\n    if (self == other) return self;\n\n    TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx1);\n    if (!ctx1) {\n        RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();\n        if (!ctx1)\n            ossl_raise(eDigestError, \"EVP_MD_CTX_new\");\n    }\n    GetDigest(other, ctx2);\n\n    if (!EVP_MD_CTX_copy(ctx1, ctx2)) {\n        ossl_raise(eDigestError, NULL);\n    }\n    return self;\n}\n\nstatic void\nadd_digest_name_to_ary(const OBJ_NAME *name, void *arg)\n{\n    VALUE ary = (VALUE)arg;\n    rb_ary_push(ary, rb_str_new2(name->name));\n}\n\n/*\n *  call-seq:\n *     OpenSSL::Digest.digests -> array[string...]\n *\n *  Returns the names of all available digests in an array.\n */\nstatic VALUE\nossl_s_digests(VALUE self)\n{\n    VALUE ary;\n\n    ary = rb_ary_new();\n    OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,\n                           add_digest_name_to_ary,\n                           (void*)ary);\n\n    return ary;\n}\n\n/*\n *  call-seq:\n *     digest.reset -> self\n *\n * Resets the Digest in the sense that any Digest#update that has been\n * performed is abandoned and the Digest is set to its initial state again.\n *\n */\nstatic VALUE\nossl_digest_reset(VALUE self)\n{\n    EVP_MD_CTX *ctx;\n\n    GetDigest(self, ctx);\n    if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) {\n        ossl_raise(eDigestError, \"Digest initialization failed.\");\n    }\n\n    return self;\n}\n\n/*\n *  call-seq:\n *     digest.update(string) -> aString\n *\n * Not every message digest can be computed in one single pass. If a message\n * digest is to be computed from several subsequent sources, then each may\n * be passed individually to the Digest instance.\n *\n * === Example\n *   digest = OpenSSL::Digest.new('SHA256')\n *   digest.update('First input')\n *   digest << 'Second input' # equivalent to digest.update('Second input')\n *   result = digest.digest\n *\n */\nstatic VALUE\nossl_digest_update(VALUE self, VALUE data)\n{\n    EVP_MD_CTX *ctx;\n\n    StringValue(data);\n    GetDigest(self, ctx);\n\n    if (!EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)))\n        ossl_raise(eDigestError, \"EVP_DigestUpdate\");\n\n    return self;\n}\n\n/*\n *  call-seq:\n *      digest.finish -> aString\n *\n */\nstatic VALUE\nossl_digest_finish(VALUE self)\n{\n    EVP_MD_CTX *ctx;\n    VALUE str;\n\n    GetDigest(self, ctx);\n    str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));\n    if (!EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL))\n        ossl_raise(eDigestError, \"EVP_DigestFinal_ex\");\n\n    return str;\n}\n\n/*\n *  call-seq:\n *      digest.name -> string\n *\n * Returns the short name of this Digest algorithm which may differ slightly\n * from the original name provided.\n *\n * === Example\n *   digest = OpenSSL::Digest.new('SHA512')\n *   puts digest.name # => SHA512\n *\n */\nstatic VALUE\nossl_digest_name(VALUE self)\n{\n    EVP_MD_CTX *ctx;\n\n    GetDigest(self, ctx);\n\n    return rb_str_new_cstr(EVP_MD_name(EVP_MD_CTX_get0_md(ctx)));\n}\n\n/*\n *  call-seq:\n *      digest.digest_length -> integer\n *\n * Returns the output size of the digest, i.e. the length in bytes of the\n * final message digest result.\n *\n * === Example\n *   digest = OpenSSL::Digest.new('SHA1')\n *   puts digest.digest_length # => 20\n *\n */\nstatic VALUE\nossl_digest_size(VALUE self)\n{\n    EVP_MD_CTX *ctx;\n\n    GetDigest(self, ctx);\n\n    return INT2NUM(EVP_MD_CTX_size(ctx));\n}\n\n/*\n *  call-seq:\n *      digest.block_length -> integer\n *\n * Returns the block length of the digest algorithm, i.e. the length in bytes\n * of an individual block. Most modern algorithms partition a message to be\n * digested into a sequence of fix-sized blocks that are processed\n * consecutively.\n *\n * === Example\n *   digest = OpenSSL::Digest.new('SHA1')\n *   puts digest.block_length # => 64\n */\nstatic VALUE\nossl_digest_block_length(VALUE self)\n{\n    EVP_MD_CTX *ctx;\n\n    GetDigest(self, ctx);\n\n    return INT2NUM(EVP_MD_CTX_block_size(ctx));\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_digest(void)\n{\n    /* Document-class: OpenSSL::Digest\n     *\n     * OpenSSL::Digest allows you to compute message digests (sometimes\n     * interchangeably called \"hashes\") of arbitrary data that are\n     * cryptographically secure, i.e. a Digest implements a secure one-way\n     * function.\n     *\n     * One-way functions offer some useful properties. E.g. given two\n     * distinct inputs the probability that both yield the same output\n     * is highly unlikely. Combined with the fact that every message digest\n     * algorithm has a fixed-length output of just a few bytes, digests are\n     * often used to create unique identifiers for arbitrary data. A common\n     * example is the creation of a unique id for binary documents that are\n     * stored in a database.\n     *\n     * Another useful characteristic of one-way functions (and thus the name)\n     * is that given a digest there is no indication about the original\n     * data that produced it, i.e. the only way to identify the original input\n     * is to \"brute-force\" through every possible combination of inputs.\n     *\n     * These characteristics make one-way functions also ideal companions\n     * for public key signature algorithms: instead of signing an entire\n     * document, first a hash of the document is produced with a considerably\n     * faster message digest algorithm and only the few bytes of its output\n     * need to be signed using the slower public key algorithm. To validate\n     * the integrity of a signed document, it suffices to re-compute the hash\n     * and verify that it is equal to that in the signature.\n     *\n     * You can get a list of all digest algorithms supported on your system by\n     * running this command in your terminal:\n     *\n     *   openssl list -digest-algorithms\n     *\n     * Among the OpenSSL 1.1.1 supported message digest algorithms are:\n     * * SHA224, SHA256, SHA384, SHA512, SHA512-224 and SHA512-256\n     * * SHA3-224, SHA3-256, SHA3-384 and SHA3-512\n     * * BLAKE2s256 and BLAKE2b512\n     *\n     * Each of these algorithms can be instantiated using the name:\n     *\n     *   digest = OpenSSL::Digest.new('SHA256')\n     *\n     * \"Breaking\" a message digest algorithm means defying its one-way\n     * function characteristics, i.e. producing a collision or finding a way\n     * to get to the original data by means that are more efficient than\n     * brute-forcing etc. Most of the supported digest algorithms can be\n     * considered broken in this sense, even the very popular MD5 and SHA1\n     * algorithms. Should security be your highest concern, then you should\n     * probably rely on SHA224, SHA256, SHA384 or SHA512.\n     *\n     * === Hashing a file\n     *\n     *   data = File.binread('document')\n     *   sha256 = OpenSSL::Digest.new('SHA256')\n     *   digest = sha256.digest(data)\n     *\n     * === Hashing several pieces of data at once\n     *\n     *   data1 = File.binread('file1')\n     *   data2 = File.binread('file2')\n     *   data3 = File.binread('file3')\n     *   sha256 = OpenSSL::Digest.new('SHA256')\n     *   sha256 << data1\n     *   sha256 << data2\n     *   sha256 << data3\n     *   digest = sha256.digest\n     *\n     * === Reuse a Digest instance\n     *\n     *   data1 = File.binread('file1')\n     *   sha256 = OpenSSL::Digest.new('SHA256')\n     *   digest1 = sha256.digest(data1)\n     *\n     *   data2 = File.binread('file2')\n     *   sha256.reset\n     *   digest2 = sha256.digest(data2)\n     *\n     */\n\n    /*\n     * Digest::Class is defined by the digest library. rb_require() cannot be\n     * used here because it bypasses RubyGems.\n     */\n    rb_funcall(Qnil, rb_intern_const(\"require\"), 1, rb_str_new_cstr(\"digest\"));\n    cDigest = rb_define_class_under(mOSSL, \"Digest\", rb_path2class(\"Digest::Class\"));\n    /* Document-class: OpenSSL::Digest::DigestError\n     *\n     * Generic Exception class that is raised if an error occurs during a\n     * Digest operation.\n     */\n    eDigestError = rb_define_class_under(cDigest, \"DigestError\", eOSSLError);\n\n    rb_define_alloc_func(cDigest, ossl_digest_alloc);\n\n    rb_define_module_function(cDigest, \"digests\", ossl_s_digests, 0);\n    rb_define_method(cDigest, \"initialize\", ossl_digest_initialize, -1);\n    rb_define_method(cDigest, \"initialize_copy\", ossl_digest_copy, 1);\n    rb_define_method(cDigest, \"reset\", ossl_digest_reset, 0);\n    rb_define_method(cDigest, \"update\", ossl_digest_update, 1);\n    rb_define_alias(cDigest, \"<<\", \"update\");\n    rb_define_private_method(cDigest, \"finish\", ossl_digest_finish, 0);\n    rb_define_method(cDigest, \"digest_length\", ossl_digest_size, 0);\n    rb_define_method(cDigest, \"block_length\", ossl_digest_block_length, 0);\n\n    rb_define_method(cDigest, \"name\", ossl_digest_name, 0);\n\n    id_md_holder = rb_intern_const(\"EVP_MD_holder\");\n}\n"
  },
  {
    "path": "ext/openssl/ossl_digest.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_DIGEST_H_)\n#define _OSSL_DIGEST_H_\n\n/*\n * Gets EVP_MD from a String or an OpenSSL::Digest instance (discouraged, but\n * still supported for compatibility). A holder object is created if the EVP_MD\n * is a \"fetched\" algorithm.\n */\nconst EVP_MD *ossl_evp_md_fetch(VALUE obj, volatile VALUE *holder);\n/*\n * This is meant for OpenSSL::Engine#digest. EVP_MD must not be a fetched one.\n */\nVALUE ossl_digest_new(const EVP_MD *);\nvoid Init_ossl_digest(void);\n\n#endif /* _OSSL_DIGEST_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_engine.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#ifdef OSSL_USE_ENGINE\n# include <openssl/engine.h>\n\n#define NewEngine(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_engine_type, 0)\n#define SetEngine(obj, engine) do { \\\n    if (!(engine)) { \\\n        ossl_raise(rb_eRuntimeError, \"ENGINE wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (engine); \\\n} while(0)\n#define GetEngine(obj, engine) do { \\\n    TypedData_Get_Struct((obj), ENGINE, &ossl_engine_type, (engine)); \\\n    if (!(engine)) { \\\n        ossl_raise(rb_eRuntimeError, \"ENGINE wasn't initialized.\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\n/* Document-class: OpenSSL::Engine\n *\n * This class is the access to openssl's ENGINE cryptographic module\n * implementation.\n *\n * See also, https://www.openssl.org/docs/crypto/engine.html\n */\nstatic VALUE cEngine;\n/* Document-class: OpenSSL::Engine::EngineError\n *\n * This is the generic exception for OpenSSL::Engine related errors\n */\nstatic VALUE eEngineError;\n\n/*\n * Private\n */\n#define OSSL_ENGINE_LOAD_IF_MATCH(engine_name, x) \\\ndo{\\\n    if(!strcmp(#engine_name, RSTRING_PTR(name))){\\\n        if (OPENSSL_init_crypto(OPENSSL_INIT_ENGINE_##x, NULL))\\\n        return Qtrue;\\\n        else\\\n        ossl_raise(eEngineError, \"OPENSSL_init_crypto\"); \\\n    }\\\n}while(0)\n\nstatic void\nossl_engine_free(void *engine)\n{\n    ENGINE_free(engine);\n}\n\nstatic const rb_data_type_t ossl_engine_type = {\n    \"OpenSSL/Engine\",\n    {\n        0, ossl_engine_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * call-seq:\n *    OpenSSL::Engine.load(name = nil)\n *\n * This method loads engines. If _name_ is nil, then all builtin engines are\n * loaded. Otherwise, the given _name_, as a String,  is loaded if available to\n * your runtime, and returns true. If _name_ is not found, then nil is\n * returned.\n *\n */\nstatic VALUE\nossl_engine_s_load(int argc, VALUE *argv, VALUE klass)\n{\n    VALUE name;\n\n    rb_scan_args(argc, argv, \"01\", &name);\n    if(NIL_P(name)){\n        ENGINE_load_builtin_engines();\n        return Qtrue;\n    }\n    StringValueCStr(name);\n    OSSL_ENGINE_LOAD_IF_MATCH(dynamic, DYNAMIC);\n    OSSL_ENGINE_LOAD_IF_MATCH(padlock, PADLOCK);\n    OSSL_ENGINE_LOAD_IF_MATCH(capi, CAPI);\n    OSSL_ENGINE_LOAD_IF_MATCH(cryptodev, CRYPTODEV);\n    OSSL_ENGINE_LOAD_IF_MATCH(openssl, OPENSSL);\n    rb_warning(\"no such builtin loader for `%\"PRIsVALUE\"'\", name);\n    return Qnil;\n}\n\n/*\n * call-seq:\n *    OpenSSL::Engine.cleanup\n *\n * It is only necessary to run cleanup when engines are loaded via\n * OpenSSL::Engine.load. However, running cleanup before exit is recommended.\n *\n * Note that this is needed and works only in OpenSSL < 1.1.0.\n */\nstatic VALUE\nossl_engine_s_cleanup(VALUE self)\n{\n    return Qnil;\n}\n\n/*\n * call-seq:\n *    OpenSSL::Engine.engines -> [engine, ...]\n *\n * Returns an array of currently loaded engines.\n */\nstatic VALUE\nossl_engine_s_engines(VALUE klass)\n{\n    ENGINE *e;\n    VALUE ary, obj;\n\n    ary = rb_ary_new();\n    for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){\n        obj = NewEngine(klass);\n        /* Need a ref count of two here because of ENGINE_free being\n         * called internally by OpenSSL when moving to the next ENGINE\n         * and by us when releasing the ENGINE reference */\n        ENGINE_up_ref(e);\n        SetEngine(obj, e);\n        rb_ary_push(ary, obj);\n    }\n\n    return ary;\n}\n\n/*\n * call-seq:\n *    OpenSSL::Engine.by_id(name) -> engine\n *\n * Fetches the engine as specified by the _id_ String.\n *\n *   OpenSSL::Engine.by_id(\"openssl\")\n *    => #<OpenSSL::Engine id=\"openssl\" name=\"Software engine support\">\n *\n * See OpenSSL::Engine.engines for the currently loaded engines.\n */\nstatic VALUE\nossl_engine_s_by_id(VALUE klass, VALUE id)\n{\n    ENGINE *e;\n    VALUE obj;\n\n    StringValueCStr(id);\n    ossl_engine_s_load(1, &id, klass);\n    obj = NewEngine(klass);\n    if(!(e = ENGINE_by_id(RSTRING_PTR(id))))\n        ossl_raise(eEngineError, NULL);\n    SetEngine(obj, e);\n    if(rb_block_given_p()) rb_yield(obj);\n    if(!ENGINE_init(e))\n        ossl_raise(eEngineError, NULL);\n    ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,\n                0, NULL, (void(*)(void))ossl_pem_passwd_cb);\n    ossl_clear_error();\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    engine.id -> string\n *\n * Gets the id for this engine.\n *\n *    OpenSSL::Engine.load\n *    OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]\n *    OpenSSL::Engine.engines.first.id\n *      #=> \"rsax\"\n */\nstatic VALUE\nossl_engine_get_id(VALUE self)\n{\n    ENGINE *e;\n    GetEngine(self, e);\n    return rb_str_new2(ENGINE_get_id(e));\n}\n\n/*\n * call-seq:\n *    engine.name -> string\n *\n * Get the descriptive name for this engine.\n *\n *    OpenSSL::Engine.load\n *    OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]\n *    OpenSSL::Engine.engines.first.name\n *      #=> \"RSAX engine support\"\n *\n */\nstatic VALUE\nossl_engine_get_name(VALUE self)\n{\n    ENGINE *e;\n    GetEngine(self, e);\n    return rb_str_new2(ENGINE_get_name(e));\n}\n\n/*\n * call-seq:\n *    engine.finish -> nil\n *\n * Releases all internal structural references for this engine.\n *\n * May raise an EngineError if the engine is unavailable\n */\nstatic VALUE\nossl_engine_finish(VALUE self)\n{\n    ENGINE *e;\n\n    GetEngine(self, e);\n    if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL);\n\n    return Qnil;\n}\n\n/*\n * call-seq:\n *   engine.cipher(name) -> OpenSSL::Cipher\n *\n * Returns a new instance of OpenSSL::Cipher by _name_, if it is available in\n * this engine.\n *\n * An EngineError will be raised if the cipher is unavailable.\n *\n *    e = OpenSSL::Engine.by_id(\"openssl\")\n *     => #<OpenSSL::Engine id=\"openssl\" name=\"Software engine support\">\n *    e.cipher(\"RC4\")\n *     => #<OpenSSL::Cipher:0x007fc5cacc3048>\n *\n */\nstatic VALUE\nossl_engine_get_cipher(VALUE self, VALUE name)\n{\n    ENGINE *e;\n    const EVP_CIPHER *ciph, *tmp;\n    int nid;\n\n    tmp = EVP_get_cipherbyname(StringValueCStr(name));\n    if(!tmp) ossl_raise(eEngineError, \"no such cipher `%\"PRIsVALUE\"'\", name);\n    nid = EVP_CIPHER_nid(tmp);\n    GetEngine(self, e);\n    ciph = ENGINE_get_cipher(e, nid);\n    if(!ciph) ossl_raise(eEngineError, NULL);\n\n    return ossl_cipher_new(ciph);\n}\n\n/*\n * call-seq:\n *   engine.digest(name) -> OpenSSL::Digest\n *\n * Returns a new instance of OpenSSL::Digest by _name_.\n *\n * Will raise an EngineError if the digest is unavailable.\n *\n *    e = OpenSSL::Engine.by_id(\"openssl\")\n *      #=> #<OpenSSL::Engine id=\"openssl\" name=\"Software engine support\">\n *    e.digest(\"SHA1\")\n *      #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>\n *    e.digest(\"zomg\")\n *      #=> OpenSSL::Engine::EngineError: no such digest `zomg'\n */\nstatic VALUE\nossl_engine_get_digest(VALUE self, VALUE name)\n{\n    ENGINE *e;\n    const EVP_MD *md, *tmp;\n    int nid;\n\n    tmp = EVP_get_digestbyname(StringValueCStr(name));\n    if(!tmp) ossl_raise(eEngineError, \"no such digest `%\"PRIsVALUE\"'\", name);\n    nid = EVP_MD_nid(tmp);\n    GetEngine(self, e);\n    md = ENGINE_get_digest(e, nid);\n    if(!md) ossl_raise(eEngineError, NULL);\n\n    return ossl_digest_new(md);\n}\n\n/*\n * call-seq:\n *    engine.load_private_key(id = nil, data = nil) -> OpenSSL::PKey\n *\n * Loads the given private key identified by _id_ and _data_.\n *\n * An EngineError is raised of the OpenSSL::PKey is unavailable.\n *\n */\nstatic VALUE\nossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)\n{\n    ENGINE *e;\n    EVP_PKEY *pkey;\n    VALUE id, data, obj;\n    char *sid, *sdata;\n\n    rb_scan_args(argc, argv, \"02\", &id, &data);\n    sid = NIL_P(id) ? NULL : StringValueCStr(id);\n    sdata = NIL_P(data) ? NULL : StringValueCStr(data);\n    GetEngine(self, e);\n    pkey = ENGINE_load_private_key(e, sid, NULL, sdata);\n    if (!pkey) ossl_raise(eEngineError, NULL);\n    obj = ossl_pkey_wrap(pkey);\n    OSSL_PKEY_SET_PRIVATE(obj);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    engine.load_public_key(id = nil, data = nil) -> OpenSSL::PKey\n *\n * Loads the given public key identified by _id_ and _data_.\n *\n * An EngineError is raised of the OpenSSL::PKey is unavailable.\n *\n */\nstatic VALUE\nossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)\n{\n    ENGINE *e;\n    EVP_PKEY *pkey;\n    VALUE id, data;\n    char *sid, *sdata;\n\n    rb_scan_args(argc, argv, \"02\", &id, &data);\n    sid = NIL_P(id) ? NULL : StringValueCStr(id);\n    sdata = NIL_P(data) ? NULL : StringValueCStr(data);\n    GetEngine(self, e);\n    pkey = ENGINE_load_public_key(e, sid, NULL, sdata);\n    if (!pkey) ossl_raise(eEngineError, NULL);\n\n    return ossl_pkey_wrap(pkey);\n}\n\n/*\n * call-seq:\n *    engine.set_default(flag)\n *\n * Set the defaults for this engine with the given _flag_.\n *\n * These flags are used to control combinations of algorithm methods.\n *\n * _flag_ can be one of the following, other flags are available depending on\n * your OS.\n *\n * [All flags]  0xFFFF\n * [No flags]   0x0000\n *\n * See also <openssl/engine.h>\n */\nstatic VALUE\nossl_engine_set_default(VALUE self, VALUE flag)\n{\n    ENGINE *e;\n    int f = NUM2INT(flag);\n\n    GetEngine(self, e);\n    ENGINE_set_default(e, f);\n\n    return Qtrue;\n}\n\n/*\n * call-seq:\n *    engine.ctrl_cmd(command, value = nil) -> engine\n *\n * Sends the given _command_ to this engine.\n *\n * Raises an EngineError if the command fails.\n */\nstatic VALUE\nossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)\n{\n    ENGINE *e;\n    VALUE cmd, val;\n    int ret;\n\n    GetEngine(self, e);\n    rb_scan_args(argc, argv, \"11\", &cmd, &val);\n    ret = ENGINE_ctrl_cmd_string(e, StringValueCStr(cmd),\n                                 NIL_P(val) ? NULL : StringValueCStr(val), 0);\n    if (!ret) ossl_raise(eEngineError, NULL);\n\n    return self;\n}\n\nstatic VALUE\nossl_engine_cmd_flag_to_name(int flag)\n{\n    switch(flag){\n      case ENGINE_CMD_FLAG_NUMERIC:  return rb_str_new2(\"NUMERIC\");\n      case ENGINE_CMD_FLAG_STRING:   return rb_str_new2(\"STRING\");\n      case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2(\"NO_INPUT\");\n      case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2(\"INTERNAL\");\n      default: return rb_str_new2(\"UNKNOWN\");\n    }\n}\n\n/*\n * call-seq:\n *    engine.cmds -> [[\"name\", \"description\", \"flags\"], ...]\n *\n * Returns an array of command definitions for the current engine\n */\nstatic VALUE\nossl_engine_get_cmds(VALUE self)\n{\n    ENGINE *e;\n    const ENGINE_CMD_DEFN *defn, *p;\n    VALUE ary, tmp;\n\n    GetEngine(self, e);\n    ary = rb_ary_new();\n    if ((defn = ENGINE_get_cmd_defns(e)) != NULL){\n        for (p = defn; p->cmd_num > 0; p++){\n            tmp = rb_ary_new();\n            rb_ary_push(tmp, rb_str_new2(p->cmd_name));\n            rb_ary_push(tmp, rb_str_new2(p->cmd_desc));\n            rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));\n            rb_ary_push(ary, tmp);\n        }\n    }\n\n    return ary;\n}\n\n/*\n * call-seq:\n *    engine.inspect -> string\n *\n * Pretty prints this engine.\n */\nstatic VALUE\nossl_engine_inspect(VALUE self)\n{\n    ENGINE *e;\n\n    GetEngine(self, e);\n    return rb_sprintf(\"#<%\"PRIsVALUE\" id=\\\"%s\\\" name=\\\"%s\\\">\",\n                      rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));\n}\n\n#define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))\n\nvoid\nInit_ossl_engine(void)\n{\n    cEngine = rb_define_class_under(mOSSL, \"Engine\", rb_cObject);\n    eEngineError = rb_define_class_under(cEngine, \"EngineError\", eOSSLError);\n\n    rb_undef_alloc_func(cEngine);\n    rb_define_singleton_method(cEngine, \"load\", ossl_engine_s_load, -1);\n    rb_define_singleton_method(cEngine, \"cleanup\", ossl_engine_s_cleanup, 0);\n    rb_define_singleton_method(cEngine, \"engines\", ossl_engine_s_engines, 0);\n    rb_define_singleton_method(cEngine, \"by_id\", ossl_engine_s_by_id, 1);\n\n    rb_define_method(cEngine, \"id\", ossl_engine_get_id, 0);\n    rb_define_method(cEngine, \"name\", ossl_engine_get_name, 0);\n    rb_define_method(cEngine, \"finish\", ossl_engine_finish, 0);\n    rb_define_method(cEngine, \"cipher\", ossl_engine_get_cipher, 1);\n    rb_define_method(cEngine, \"digest\",  ossl_engine_get_digest, 1);\n    rb_define_method(cEngine, \"load_private_key\", ossl_engine_load_privkey, -1);\n    rb_define_method(cEngine, \"load_public_key\", ossl_engine_load_pubkey, -1);\n    rb_define_method(cEngine, \"set_default\", ossl_engine_set_default, 1);\n    rb_define_method(cEngine, \"ctrl_cmd\", ossl_engine_ctrl_cmd, -1);\n    rb_define_method(cEngine, \"cmds\", ossl_engine_get_cmds, 0);\n    rb_define_method(cEngine, \"inspect\", ossl_engine_inspect, 0);\n\n    DefEngineConst(METHOD_RSA);\n    DefEngineConst(METHOD_DSA);\n    DefEngineConst(METHOD_DH);\n    DefEngineConst(METHOD_RAND);\n    DefEngineConst(METHOD_CIPHERS);\n    DefEngineConst(METHOD_DIGESTS);\n    DefEngineConst(METHOD_ALL);\n    DefEngineConst(METHOD_NONE);\n}\n#else\nvoid\nInit_ossl_engine(void)\n{\n}\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_engine.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2003  Michal Rokos <m.rokos@sh.cvut.cz>\n * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(OSSL_ENGINE_H)\n#define OSSL_ENGINE_H\n\nvoid Init_ossl_engine(void);\n\n#endif /* OSSL_ENGINE_H */\n"
  },
  {
    "path": "ext/openssl/ossl_hmac.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewHMAC(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0)\n#define GetHMAC(obj, ctx) do { \\\n    TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \\\n    if (!(ctx)) { \\\n        ossl_raise(rb_eRuntimeError, \"HMAC wasn't initialized\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nstatic VALUE cHMAC;\nstatic VALUE eHMACError;\nstatic ID id_md_holder;\n\n/*\n * Public\n */\n\n/*\n * Private\n */\nstatic void\nossl_hmac_free(void *ctx)\n{\n    EVP_MD_CTX_free(ctx);\n}\n\nstatic const rb_data_type_t ossl_hmac_type = {\n    \"OpenSSL/HMAC\",\n    {\n        0, ossl_hmac_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_hmac_alloc(VALUE klass)\n{\n    VALUE obj;\n    EVP_MD_CTX *ctx;\n\n    obj = NewHMAC(klass);\n    ctx = EVP_MD_CTX_new();\n    if (!ctx)\n        ossl_raise(eHMACError, \"EVP_MD_CTX\");\n    RTYPEDDATA_DATA(obj) = ctx;\n\n    return obj;\n}\n\n\n/*\n *  call-seq:\n *     HMAC.new(key, digest) -> hmac\n *\n * Returns an instance of OpenSSL::HMAC set with the key and digest\n * algorithm to be used. The instance represents the initial state of\n * the message authentication code before any data has been processed.\n * To process data with it, use the instance method #update with your\n * data as an argument.\n *\n * === Example\n *\n *      key = 'key'\n *      instance = OpenSSL::HMAC.new(key, 'SHA1')\n *      #=> f42bb0eeb018ebbd4597ae7213711ec60760843f\n *      instance.class\n *      #=> OpenSSL::HMAC\n *\n * === A note about comparisons\n *\n * Two instances can be securely compared with #== in constant time:\n *\n *      other_instance = OpenSSL::HMAC.new('key', 'SHA1')\n *  #=> f42bb0eeb018ebbd4597ae7213711ec60760843f\n *  instance == other_instance\n *  #=> true\n *\n */\nstatic VALUE\nossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)\n{\n    EVP_MD_CTX *ctx;\n    EVP_PKEY *pkey;\n    const EVP_MD *md;\n    VALUE md_holder;\n\n    GetHMAC(self, ctx);\n    StringValue(key);\n    md = ossl_evp_md_fetch(digest, &md_holder);\n    pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,\n                                        (unsigned char *)RSTRING_PTR(key),\n                                        RSTRING_LENINT(key));\n    if (!pkey)\n        ossl_raise(eHMACError, \"EVP_PKEY_new_raw_private_key\");\n    if (EVP_DigestSignInit(ctx, NULL, md, NULL, pkey) != 1) {\n        EVP_PKEY_free(pkey);\n        ossl_raise(eHMACError, \"EVP_DigestSignInit\");\n    }\n    rb_ivar_set(self, id_md_holder, md_holder);\n    /* Decrement reference counter; EVP_MD_CTX still keeps it */\n    EVP_PKEY_free(pkey);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_hmac_copy(VALUE self, VALUE other)\n{\n    EVP_MD_CTX *ctx1, *ctx2;\n\n    rb_check_frozen(self);\n    if (self == other) return self;\n\n    GetHMAC(self, ctx1);\n    GetHMAC(other, ctx2);\n    if (EVP_MD_CTX_copy(ctx1, ctx2) != 1)\n        ossl_raise(eHMACError, \"EVP_MD_CTX_copy\");\n    return self;\n}\n\n/*\n *  call-seq:\n *     hmac.update(string) -> self\n *\n * Returns _hmac_ updated with the message to be authenticated.\n * Can be called repeatedly with chunks of the message.\n *\n * === Example\n *\n *      first_chunk = 'The quick brown fox jumps '\n *      second_chunk = 'over the lazy dog'\n *\n *      instance.update(first_chunk)\n *      #=> 5b9a8038a65d571076d97fe783989e52278a492a\n *      instance.update(second_chunk)\n *      #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9\n *\n */\nstatic VALUE\nossl_hmac_update(VALUE self, VALUE data)\n{\n    EVP_MD_CTX *ctx;\n\n    StringValue(data);\n    GetHMAC(self, ctx);\n    if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)\n        ossl_raise(eHMACError, \"EVP_DigestSignUpdate\");\n\n    return self;\n}\n\n/*\n *  call-seq:\n *     hmac.digest -> string\n *\n * Returns the authentication code an instance represents as a binary string.\n *\n * === Example\n *  instance = OpenSSL::HMAC.new('key', 'SHA1')\n *  #=> f42bb0eeb018ebbd4597ae7213711ec60760843f\n *  instance.digest\n *  #=> \"\\xF4+\\xB0\\xEE\\xB0\\x18\\xEB\\xBDE\\x97\\xAEr\\x13q\\x1E\\xC6\\a`\\x84?\"\n */\nstatic VALUE\nossl_hmac_digest(VALUE self)\n{\n    EVP_MD_CTX *ctx;\n    size_t buf_len = EVP_MAX_MD_SIZE;\n    VALUE ret;\n\n    GetHMAC(self, ctx);\n    ret = rb_str_new(NULL, EVP_MAX_MD_SIZE);\n    if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(ret),\n                            &buf_len) != 1)\n        ossl_raise(eHMACError, \"EVP_DigestSignFinal\");\n    rb_str_set_len(ret, (long)buf_len);\n\n    return ret;\n}\n\n/*\n *  call-seq:\n *     hmac.hexdigest -> string\n *\n * Returns the authentication code an instance represents as a hex-encoded\n * string.\n */\nstatic VALUE\nossl_hmac_hexdigest(VALUE self)\n{\n    EVP_MD_CTX *ctx;\n    unsigned char buf[EVP_MAX_MD_SIZE];\n    size_t buf_len = EVP_MAX_MD_SIZE;\n    VALUE ret;\n\n    GetHMAC(self, ctx);\n    if (EVP_DigestSignFinal(ctx, buf, &buf_len) != 1)\n        ossl_raise(eHMACError, \"EVP_DigestSignFinal\");\n    ret = rb_str_new(NULL, buf_len * 2);\n    ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);\n\n    return ret;\n}\n\n/*\n *  call-seq:\n *     hmac.reset -> self\n *\n * Returns _hmac_ as it was when it was first initialized, with all processed\n * data cleared from it.\n *\n * === Example\n *\n *      data = \"The quick brown fox jumps over the lazy dog\"\n *      instance = OpenSSL::HMAC.new('key', 'SHA1')\n *      #=> f42bb0eeb018ebbd4597ae7213711ec60760843f\n *\n *      instance.update(data)\n *      #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9\n *      instance.reset\n *      #=> f42bb0eeb018ebbd4597ae7213711ec60760843f\n *\n */\nstatic VALUE\nossl_hmac_reset(VALUE self)\n{\n    EVP_MD_CTX *ctx;\n    EVP_PKEY *pkey;\n\n    GetHMAC(self, ctx);\n    pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx));\n    if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_get0_md(ctx), NULL, pkey) != 1)\n        ossl_raise(eHMACError, \"EVP_DigestSignInit\");\n\n    return self;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_hmac(void)\n{\n    /*\n     * Document-class: OpenSSL::HMAC\n     *\n     * OpenSSL::HMAC allows computing Hash-based Message Authentication Code\n     * (HMAC). It is a type of message authentication code (MAC) involving a\n     * hash function in combination with a key. HMAC can be used to verify the\n     * integrity of a message as well as the authenticity.\n     *\n     * OpenSSL::HMAC has a similar interface to OpenSSL::Digest.\n     *\n     * === HMAC-SHA256 using one-shot interface\n     *\n     *   key = \"key\"\n     *   data = \"message-to-be-authenticated\"\n     *   mac = OpenSSL::HMAC.hexdigest(\"SHA256\", key, data)\n     *   #=> \"cddb0db23f469c8bf072b21fd837149bd6ace9ab771cceef14c9e517cc93282e\"\n     *\n     * === HMAC-SHA256 using incremental interface\n     *\n     *   data1 = File.binread(\"file1\")\n     *   data2 = File.binread(\"file2\")\n     *   key = \"key\"\n     *   hmac = OpenSSL::HMAC.new(key, 'SHA256')\n     *   hmac << data1\n     *   hmac << data2\n     *   mac = hmac.digest\n     */\n    eHMACError = rb_define_class_under(mOSSL, \"HMACError\", eOSSLError);\n\n    cHMAC = rb_define_class_under(mOSSL, \"HMAC\", rb_cObject);\n\n    rb_define_alloc_func(cHMAC, ossl_hmac_alloc);\n\n    rb_define_method(cHMAC, \"initialize\", ossl_hmac_initialize, 2);\n    rb_define_method(cHMAC, \"initialize_copy\", ossl_hmac_copy, 1);\n\n    rb_define_method(cHMAC, \"reset\", ossl_hmac_reset, 0);\n    rb_define_method(cHMAC, \"update\", ossl_hmac_update, 1);\n    rb_define_alias(cHMAC, \"<<\", \"update\");\n    rb_define_method(cHMAC, \"digest\", ossl_hmac_digest, 0);\n    rb_define_method(cHMAC, \"hexdigest\", ossl_hmac_hexdigest, 0);\n    rb_define_alias(cHMAC, \"inspect\", \"hexdigest\");\n    rb_define_alias(cHMAC, \"to_s\", \"hexdigest\");\n\n    id_md_holder = rb_intern_const(\"EVP_MD_holder\");\n}\n"
  },
  {
    "path": "ext/openssl/ossl_hmac.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_HMAC_H_)\n#define _OSSL_HMAC_H_\n\nvoid Init_ossl_hmac(void);\n\n#endif /* _OSSL_HMAC_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_kdf.c",
    "content": "/*\n * Ruby/OpenSSL Project\n * Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors\n */\n#include \"ossl.h\"\n#include <openssl/kdf.h>\n\nstatic VALUE mKDF, eKDF;\n\nstruct pbkdf2_hmac_args {\n    char *pass;\n    int passlen;\n    unsigned char *salt;\n    int saltlen;\n    int iters;\n    const EVP_MD *md;\n    int len;\n    unsigned char *out;\n};\n\nstatic void *\npbkdf2_hmac_nogvl(void *args_)\n{\n    struct pbkdf2_hmac_args *args = (struct pbkdf2_hmac_args *)args_;\n    int ret = PKCS5_PBKDF2_HMAC(args->pass, args->passlen, args->salt,\n                                args->saltlen, args->iters, args->md,\n                                args->len, args->out);\n    return (void *)(uintptr_t)ret;\n}\n\n/*\n * call-seq:\n *   KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString\n *\n * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in combination\n * with HMAC. Takes _pass_, _salt_ and _iterations_, and then derives a key\n * of _length_ bytes.\n *\n * For more information about PBKDF2, see RFC 2898 Section 5.2\n * (https://www.rfc-editor.org/rfc/rfc2898#section-5.2).\n *\n * === Parameters\n * pass       :: The password.\n * salt       :: The salt. Salts prevent attacks based on dictionaries of common\n *               passwords and attacks based on rainbow tables. It is a public\n *               value that can be safely stored along with the password (e.g.\n *               if the derived value is used for password storage).\n * iterations :: The iteration count. This provides the ability to tune the\n *               algorithm. It is better to use the highest count possible for\n *               the maximum resistance to brute-force attacks.\n * length     :: The desired length of the derived key in octets.\n * hash       :: The hash algorithm used with HMAC for the PRF. May be a String\n *               representing the algorithm name, or an instance of\n *               OpenSSL::Digest.\n */\nstatic VALUE\nkdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)\n{\n    VALUE pass, salt, opts, kwargs[4], str, md_holder, pass_tmp, salt_tmp;\n    static ID kwargs_ids[4];\n    int passlen, saltlen, iters, len;\n    const EVP_MD *md;\n\n    if (!kwargs_ids[0]) {\n        kwargs_ids[0] = rb_intern_const(\"salt\");\n        kwargs_ids[1] = rb_intern_const(\"iterations\");\n        kwargs_ids[2] = rb_intern_const(\"length\");\n        kwargs_ids[3] = rb_intern_const(\"hash\");\n    }\n    rb_scan_args(argc, argv, \"1:\", &pass, &opts);\n    rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);\n\n    StringValue(pass);\n    salt = StringValue(kwargs[0]);\n    iters = NUM2INT(kwargs[1]);\n    len = NUM2INT(kwargs[2]);\n    md = ossl_evp_md_fetch(kwargs[3], &md_holder);\n    passlen = RSTRING_LENINT(pass);\n    saltlen = RSTRING_LENINT(salt);\n    str = rb_str_new(NULL, len);\n    struct pbkdf2_hmac_args args = {\n        .pass = ALLOCV(pass_tmp, passlen),\n        .passlen = passlen,\n        .salt = ALLOCV(salt_tmp, saltlen),\n        .saltlen = saltlen,\n        .iters = iters,\n        .md = md,\n        .len = len,\n        .out = (unsigned char *)RSTRING_PTR(str),\n    };\n    memcpy(args.pass, RSTRING_PTR(pass), passlen);\n    memcpy(args.salt, RSTRING_PTR(salt), saltlen);\n    if (!rb_thread_call_without_gvl(pbkdf2_hmac_nogvl, &args, NULL, NULL))\n        ossl_raise(eKDF, \"PKCS5_PBKDF2_HMAC\");\n    OPENSSL_cleanse(args.pass, passlen);\n    ALLOCV_END(pass_tmp);\n    ALLOCV_END(salt_tmp);\n    return str;\n}\n\n#if defined(HAVE_EVP_PBE_SCRYPT)\nstruct scrypt_args {\n    char *pass;\n    size_t passlen;\n    unsigned char *salt;\n    size_t saltlen;\n    uint64_t N, r, p;\n    size_t len;\n    unsigned char *out;\n};\n\nstatic void *\nscrypt_nogvl(void *args_)\n{\n    struct scrypt_args *args = (struct scrypt_args *)args_;\n    /*\n     * OpenSSL uses 32MB by default (if zero is specified), which is too\n     * small. Let's not limit memory consumption but just let malloc() fail\n     * inside OpenSSL. The amount is controllable by other parameters.\n     */\n    uint64_t maxmem = UINT64_MAX;\n    int ret = EVP_PBE_scrypt(args->pass, args->passlen,\n                             args->salt, args->saltlen, args->N, args->r,\n                             args->p, maxmem, args->out, args->len);\n    return (void *)(uintptr_t)ret;\n}\n\n/*\n * call-seq:\n *   KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString\n *\n * Derives a key from _pass_ using given parameters with the scrypt\n * password-based key derivation function. The result can be used for password\n * storage.\n *\n * scrypt is designed to be memory-hard and more secure against brute-force\n * attacks using custom hardwares than alternative KDFs such as PBKDF2 or\n * bcrypt.\n *\n * The keyword arguments _N_, _r_ and _p_ can be used to tune scrypt. RFC 7914\n * (published on 2016-08, https://www.rfc-editor.org/rfc/rfc7914#section-2) states\n * that using values r=8 and p=1 appears to yield good results.\n *\n * See RFC 7914 (https://www.rfc-editor.org/rfc/rfc7914) for more information.\n *\n * === Parameters\n * pass   :: Passphrase.\n * salt   :: Salt.\n * N      :: CPU/memory cost parameter. This must be a power of 2.\n * r      :: Block size parameter.\n * p      :: Parallelization parameter.\n * length :: Length in octets of the derived key.\n *\n * === Example\n *   pass = \"password\"\n *   salt = SecureRandom.random_bytes(16)\n *   dk = OpenSSL::KDF.scrypt(pass, salt: salt, N: 2**14, r: 8, p: 1, length: 32)\n *   p dk #=> \"\\xDA\\xE4\\xE2...\\x7F\\xA1\\x01T\"\n */\nstatic VALUE\nkdf_scrypt(int argc, VALUE *argv, VALUE self)\n{\n    VALUE pass, salt, opts, kwargs[5], str, pass_tmp, salt_tmp;\n    static ID kwargs_ids[5];\n    size_t passlen, saltlen;\n    long len;\n    uint64_t N, r, p;\n\n    if (!kwargs_ids[0]) {\n        kwargs_ids[0] = rb_intern_const(\"salt\");\n        kwargs_ids[1] = rb_intern_const(\"N\");\n        kwargs_ids[2] = rb_intern_const(\"r\");\n        kwargs_ids[3] = rb_intern_const(\"p\");\n        kwargs_ids[4] = rb_intern_const(\"length\");\n    }\n    rb_scan_args(argc, argv, \"1:\", &pass, &opts);\n    rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs);\n\n    StringValue(pass);\n    salt = StringValue(kwargs[0]);\n    N = NUM2UINT64T(kwargs[1]);\n    r = NUM2UINT64T(kwargs[2]);\n    p = NUM2UINT64T(kwargs[3]);\n    len = NUM2LONG(kwargs[4]);\n    passlen = RSTRING_LEN(pass);\n    saltlen = RSTRING_LEN(salt);\n    str = rb_str_new(NULL, len);\n    struct scrypt_args args = {\n        .pass = ALLOCV(pass_tmp, passlen),\n        .passlen = passlen,\n        .salt = ALLOCV(salt_tmp, saltlen),\n        .saltlen = saltlen,\n        .N = N,\n        .r = r,\n        .p = p,\n        .len = len,\n        .out = (unsigned char *)RSTRING_PTR(str),\n    };\n    memcpy(args.pass, RSTRING_PTR(pass), passlen);\n    memcpy(args.salt, RSTRING_PTR(salt), saltlen);\n    if (!rb_thread_call_without_gvl(scrypt_nogvl, &args, NULL, NULL))\n        ossl_raise(eKDF, \"EVP_PBE_scrypt\");\n    OPENSSL_cleanse(args.pass, passlen);\n    ALLOCV_END(pass_tmp);\n    ALLOCV_END(salt_tmp);\n    return str;\n}\n#endif\n\n/*\n * call-seq:\n *    KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String\n *\n * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as specified in\n * {RFC 5869}[https://www.rfc-editor.org/rfc/rfc5869].\n *\n * New in OpenSSL 1.1.0.\n *\n * === Parameters\n * _ikm_::\n *   The input keying material.\n * _salt_::\n *   The salt.\n * _info_::\n *   The context and application specific information.\n * _length_::\n *   The output length in octets. Must be <= <tt>255 * HashLen</tt>, where\n *   HashLen is the length of the hash function output in octets.\n * _hash_::\n *   The hash function.\n *\n * === Example\n *   # The values from https://www.rfc-editor.org/rfc/rfc5869#appendix-A.1\n *   ikm = [\"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\"].pack(\"H*\")\n *   salt = [\"000102030405060708090a0b0c\"].pack(\"H*\")\n *   info = [\"f0f1f2f3f4f5f6f7f8f9\"].pack(\"H*\")\n *   p OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: 42, hash: \"SHA256\").unpack1(\"H*\")\n *   # => \"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865\"\n */\nstatic VALUE\nkdf_hkdf(int argc, VALUE *argv, VALUE self)\n{\n    VALUE ikm, salt, info, opts, kwargs[4], str, md_holder;\n    static ID kwargs_ids[4];\n    int saltlen, ikmlen, infolen;\n    size_t len;\n    const EVP_MD *md;\n    EVP_PKEY_CTX *pctx;\n\n    if (!kwargs_ids[0]) {\n        kwargs_ids[0] = rb_intern_const(\"salt\");\n        kwargs_ids[1] = rb_intern_const(\"info\");\n        kwargs_ids[2] = rb_intern_const(\"length\");\n        kwargs_ids[3] = rb_intern_const(\"hash\");\n    }\n    rb_scan_args(argc, argv, \"1:\", &ikm, &opts);\n    rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);\n\n    StringValue(ikm);\n    ikmlen = RSTRING_LENINT(ikm);\n    salt = StringValue(kwargs[0]);\n    saltlen = RSTRING_LENINT(salt);\n    info = StringValue(kwargs[1]);\n    infolen = RSTRING_LENINT(info);\n    len = (size_t)NUM2LONG(kwargs[2]);\n    if (len > LONG_MAX)\n        rb_raise(rb_eArgError, \"length must be non-negative\");\n    md = ossl_evp_md_fetch(kwargs[3], &md_holder);\n\n    str = rb_str_new(NULL, (long)len);\n    pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);\n    if (!pctx)\n        ossl_raise(eKDF, \"EVP_PKEY_CTX_new_id\");\n    if (EVP_PKEY_derive_init(pctx) <= 0) {\n        EVP_PKEY_CTX_free(pctx);\n        ossl_raise(eKDF, \"EVP_PKEY_derive_init\");\n    }\n    if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {\n        EVP_PKEY_CTX_free(pctx);\n        ossl_raise(eKDF, \"EVP_PKEY_CTX_set_hkdf_md\");\n    }\n    if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),\n                                    saltlen) <= 0) {\n        EVP_PKEY_CTX_free(pctx);\n        ossl_raise(eKDF, \"EVP_PKEY_CTX_set_hkdf_salt\");\n    }\n    if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),\n                                   ikmlen) <= 0) {\n        EVP_PKEY_CTX_free(pctx);\n        ossl_raise(eKDF, \"EVP_PKEY_CTX_set_hkdf_key\");\n    }\n    if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),\n                                    infolen) <= 0) {\n        EVP_PKEY_CTX_free(pctx);\n        ossl_raise(eKDF, \"EVP_PKEY_CTX_set_hkdf_info\");\n    }\n    if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {\n        EVP_PKEY_CTX_free(pctx);\n        ossl_raise(eKDF, \"EVP_PKEY_derive\");\n    }\n    rb_str_set_len(str, (long)len);\n    EVP_PKEY_CTX_free(pctx);\n\n    return str;\n}\n\nvoid\nInit_ossl_kdf(void)\n{\n    /*\n     * Document-module: OpenSSL::KDF\n     *\n     * Provides functionality of various KDFs (key derivation function).\n     *\n     * KDF is typically used for securely deriving arbitrary length symmetric\n     * keys to be used with an OpenSSL::Cipher from passwords. Another use case\n     * is for storing passwords: Due to the ability to tweak the effort of\n     * computation by increasing the iteration count, computation can be slowed\n     * down artificially in order to render possible attacks infeasible.\n     *\n     * Currently, OpenSSL::KDF provides implementations for the following KDF:\n     *\n     * * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in\n     *   combination with HMAC\n     * * scrypt\n     * * HKDF\n     *\n     * == Examples\n     * === Generating a 128 bit key for a Cipher (e.g. AES)\n     *   pass = \"secret\"\n     *   salt = OpenSSL::Random.random_bytes(16)\n     *   iter = 20_000\n     *   key_len = 16\n     *   key = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,\n     *                                  length: key_len, hash: \"sha1\")\n     *\n     * === Storing Passwords\n     *   pass = \"secret\"\n     *   # store this with the generated value\n     *   salt = OpenSSL::Random.random_bytes(16)\n     *   iter = 20_000\n     *   hash = OpenSSL::Digest.new('SHA256')\n     *   len = hash.digest_length\n     *   # the final value to be stored\n     *   value = OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,\n     *                                    length: len, hash: hash)\n     *\n     * == Important Note on Checking Passwords\n     * When comparing passwords provided by the user with previously stored\n     * values, a common mistake made is comparing the two values using \"==\".\n     * Typically, \"==\" short-circuits on evaluation, and is therefore\n     * vulnerable to timing attacks. The proper way is to use a method that\n     * always takes the same amount of time when comparing two values, thus\n     * not leaking any information to potential attackers. To do this, use\n     * +OpenSSL.fixed_length_secure_compare+.\n     */\n    mKDF = rb_define_module_under(mOSSL, \"KDF\");\n    /*\n     * Generic exception class raised if an error occurs in OpenSSL::KDF module.\n     */\n    eKDF = rb_define_class_under(mKDF, \"KDFError\", eOSSLError);\n\n    rb_define_module_function(mKDF, \"pbkdf2_hmac\", kdf_pbkdf2_hmac, -1);\n#if defined(HAVE_EVP_PBE_SCRYPT)\n    rb_define_module_function(mKDF, \"scrypt\", kdf_scrypt, -1);\n#endif\n    rb_define_module_function(mKDF, \"hkdf\", kdf_hkdf, -1);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_kdf.h",
    "content": "#if !defined(OSSL_KDF_H)\n#define OSSL_KDF_H\n\nvoid Init_ossl_kdf(void);\n\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_ns_spki.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewSPKI(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_netscape_spki_type, 0)\n#define SetSPKI(obj, spki) do { \\\n    if (!(spki)) { \\\n        ossl_raise(rb_eRuntimeError, \"SPKI wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (spki); \\\n} while (0)\n#define GetSPKI(obj, spki) do { \\\n    TypedData_Get_Struct((obj), NETSCAPE_SPKI, &ossl_netscape_spki_type, (spki)); \\\n    if (!(spki)) { \\\n        ossl_raise(rb_eRuntimeError, \"SPKI wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nstatic VALUE mNetscape;\nstatic VALUE cSPKI;\nstatic VALUE eSPKIError;\n\n/*\n * Public functions\n */\n\n/*\n * Private functions\n */\n\nstatic void\nossl_netscape_spki_free(void *spki)\n{\n    NETSCAPE_SPKI_free(spki);\n}\n\nstatic const rb_data_type_t ossl_netscape_spki_type = {\n    \"OpenSSL/NETSCAPE_SPKI\",\n    {\n        0, ossl_netscape_spki_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_spki_alloc(VALUE klass)\n{\n    NETSCAPE_SPKI *spki;\n    VALUE obj;\n\n    obj = NewSPKI(klass);\n    if (!(spki = NETSCAPE_SPKI_new())) {\n        ossl_raise(eSPKIError, NULL);\n    }\n    SetSPKI(obj, spki);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    SPKI.new([request]) => spki\n *\n * === Parameters\n * * _request_ - optional raw request, either in PEM or DER format.\n */\nstatic VALUE\nossl_spki_initialize(int argc, VALUE *argv, VALUE self)\n{\n    NETSCAPE_SPKI *spki;\n    VALUE buffer;\n    const unsigned char *p;\n\n    if (rb_scan_args(argc, argv, \"01\", &buffer) == 0) {\n        return self;\n    }\n    StringValue(buffer);\n    if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), RSTRING_LENINT(buffer)))) {\n        ossl_clear_error();\n        p = (unsigned char *)RSTRING_PTR(buffer);\n        if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {\n            ossl_raise(eSPKIError, NULL);\n        }\n    }\n    NETSCAPE_SPKI_free(DATA_PTR(self));\n    SetSPKI(self, spki);\n\n    return self;\n}\n\n/*\n * call-seq:\n *    spki.to_der => DER-encoded string\n *\n * Returns the DER encoding of this SPKI.\n */\nstatic VALUE\nossl_spki_to_der(VALUE self)\n{\n    NETSCAPE_SPKI *spki;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetSPKI(self, spki);\n    if ((len = i2d_NETSCAPE_SPKI(spki, NULL)) <= 0)\n        ossl_raise(eSPKIError, \"i2d_NETSCAPE_SPKI\");\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_NETSCAPE_SPKI(spki, &p) <= 0)\n        ossl_raise(eSPKIError, \"i2d_NETSCAPE_SPKI\");\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * call-seq:\n *    spki.to_pem => PEM-encoded string\n *\n * Returns the PEM encoding of this SPKI.\n */\nstatic VALUE\nossl_spki_to_pem(VALUE self)\n{\n    NETSCAPE_SPKI *spki;\n    char *data;\n    VALUE str;\n\n    GetSPKI(self, spki);\n    if (!(data = NETSCAPE_SPKI_b64_encode(spki))) {\n        ossl_raise(eSPKIError, NULL);\n    }\n    str = ossl_buf2str(data, rb_long2int(strlen(data)));\n\n    return str;\n}\n\n/*\n * call-seq:\n *    spki.to_text => string\n *\n * Returns a textual representation of this SPKI, useful for debugging\n * purposes.\n */\nstatic VALUE\nossl_spki_print(VALUE self)\n{\n    NETSCAPE_SPKI *spki;\n    BIO *out;\n\n    GetSPKI(self, spki);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eSPKIError, NULL);\n    }\n    if (!NETSCAPE_SPKI_print(out, spki)) {\n        BIO_free(out);\n        ossl_raise(eSPKIError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\n/*\n * call-seq:\n *    spki.public_key => pkey\n *\n * Returns the public key associated with the SPKI, an instance of\n * OpenSSL::PKey.\n */\nstatic VALUE\nossl_spki_get_public_key(VALUE self)\n{\n    NETSCAPE_SPKI *spki;\n    EVP_PKEY *pkey;\n\n    GetSPKI(self, spki);\n    if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */\n        ossl_raise(eSPKIError, NULL);\n    }\n\n    return ossl_pkey_wrap(pkey);\n}\n\n/*\n * call-seq:\n *    spki.public_key = pub => pkey\n *\n * === Parameters\n * * _pub_ - the public key to be set for this instance\n *\n * Sets the public key to be associated with the SPKI, an instance of\n * OpenSSL::PKey. This should be the public key corresponding to the\n * private key used for signing the SPKI.\n */\nstatic VALUE\nossl_spki_set_public_key(VALUE self, VALUE key)\n{\n    NETSCAPE_SPKI *spki;\n    EVP_PKEY *pkey;\n\n    GetSPKI(self, spki);\n    pkey = GetPKeyPtr(key);\n    ossl_pkey_check_public_key(pkey);\n    if (!NETSCAPE_SPKI_set_pubkey(spki, pkey))\n        ossl_raise(eSPKIError, \"NETSCAPE_SPKI_set_pubkey\");\n    return key;\n}\n\n/*\n * call-seq:\n *    spki.challenge => string\n *\n * Returns the challenge string associated with this SPKI.\n */\nstatic VALUE\nossl_spki_get_challenge(VALUE self)\n{\n    NETSCAPE_SPKI *spki;\n\n    GetSPKI(self, spki);\n    if (ASN1_STRING_length(spki->spkac->challenge) <= 0) {\n        OSSL_Debug(\"Challenge.length <= 0?\");\n        return rb_str_new(0, 0);\n    }\n\n    return asn1str_to_str(spki->spkac->challenge);\n}\n\n/*\n * call-seq:\n *    spki.challenge = str => string\n *\n * === Parameters\n * * _str_ - the challenge string to be set for this instance\n *\n * Sets the challenge to be associated with the SPKI. May be used by the\n * server, e.g. to prevent replay.\n */\nstatic VALUE\nossl_spki_set_challenge(VALUE self, VALUE str)\n{\n    NETSCAPE_SPKI *spki;\n\n    StringValue(str);\n    GetSPKI(self, spki);\n    if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str),\n                         RSTRING_LENINT(str))) {\n        ossl_raise(eSPKIError, NULL);\n    }\n\n    return str;\n}\n\n/*\n * call-seq:\n *    spki.sign(key, digest) => spki\n *\n * === Parameters\n * * _key_ - the private key to be used for signing this instance\n * * _digest_ - the digest to be used for signing this instance\n *\n * To sign an SPKI, the private key corresponding to the public key set\n * for this instance should be used, in addition to a digest algorithm in\n * the form of an OpenSSL::Digest. The private key should be an instance of\n * OpenSSL::PKey.\n */\nstatic VALUE\nossl_spki_sign(VALUE self, VALUE key, VALUE digest)\n{\n    NETSCAPE_SPKI *spki;\n    EVP_PKEY *pkey;\n    const EVP_MD *md;\n    VALUE md_holder;\n\n    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */\n    md = ossl_evp_md_fetch(digest, &md_holder);\n    GetSPKI(self, spki);\n    if (!NETSCAPE_SPKI_sign(spki, pkey, md))\n        ossl_raise(eSPKIError, \"NETSCAPE_SPKI_sign\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *    spki.verify(key) => boolean\n *\n * === Parameters\n * * _key_ - the public key to be used for verifying the SPKI signature\n *\n * Returns +true+ if the signature is valid, +false+ otherwise. To verify an\n * SPKI, the public key contained within the SPKI should be used.\n */\nstatic VALUE\nossl_spki_verify(VALUE self, VALUE key)\n{\n    NETSCAPE_SPKI *spki;\n    EVP_PKEY *pkey;\n\n    GetSPKI(self, spki);\n    pkey = GetPKeyPtr(key);\n    ossl_pkey_check_public_key(pkey);\n    switch (NETSCAPE_SPKI_verify(spki, pkey)) {\n      case 0:\n        ossl_clear_error();\n        return Qfalse;\n      case 1:\n        return Qtrue;\n      default:\n        ossl_raise(eSPKIError, \"NETSCAPE_SPKI_verify\");\n    }\n}\n\n/* Document-class: OpenSSL::Netscape::SPKI\n *\n * A Simple Public Key Infrastructure implementation (pronounced \"spooky\").\n * The structure is defined as\n *   PublicKeyAndChallenge ::= SEQUENCE {\n *     spki SubjectPublicKeyInfo,\n *     challenge IA5STRING\n *   }\n *\n *   SignedPublicKeyAndChallenge ::= SEQUENCE {\n *     publicKeyAndChallenge PublicKeyAndChallenge,\n *     signatureAlgorithm AlgorithmIdentifier,\n *     signature BIT STRING\n *   }\n * where the definitions of SubjectPublicKeyInfo and AlgorithmIdentifier can\n * be found in RFC5280. SPKI is typically used in browsers for generating\n * a public/private key pair and a subsequent certificate request, using\n * the HTML <keygen> element.\n *\n * == Examples\n *\n * === Creating an SPKI\n *   key = OpenSSL::PKey::RSA.new 2048\n *   spki = OpenSSL::Netscape::SPKI.new\n *   spki.challenge = \"RandomChallenge\"\n *   spki.public_key = key.public_key\n *   spki.sign(key, OpenSSL::Digest.new('SHA256'))\n *   #send a request containing this to a server generating a certificate\n * === Verifying an SPKI request\n *   request = #...\n *   spki = OpenSSL::Netscape::SPKI.new request\n *   unless spki.verify(spki.public_key)\n *     # signature is invalid\n *   end\n *   #proceed\n */\n\n/* Document-module: OpenSSL::Netscape\n *\n * OpenSSL::Netscape is a namespace for SPKI (Simple Public Key\n * Infrastructure) which implements Signed Public Key and Challenge.\n * See {RFC 2692}[https://www.rfc-editor.org/rfc/rfc2692] and {RFC\n * 2693}[https://www.rfc-editor.org/rfc/rfc2692] for details.\n */\n\n/* Document-class: OpenSSL::Netscape::SPKIError\n *\n * Generic Exception class that is raised if an error occurs during an\n * operation on an instance of OpenSSL::Netscape::SPKI.\n */\n\nvoid\nInit_ossl_ns_spki(void)\n{\n    mNetscape = rb_define_module_under(mOSSL, \"Netscape\");\n\n    eSPKIError = rb_define_class_under(mNetscape, \"SPKIError\", eOSSLError);\n\n    cSPKI = rb_define_class_under(mNetscape, \"SPKI\", rb_cObject);\n\n    rb_define_alloc_func(cSPKI, ossl_spki_alloc);\n    rb_define_method(cSPKI, \"initialize\", ossl_spki_initialize, -1);\n\n    rb_define_method(cSPKI, \"to_der\", ossl_spki_to_der, 0);\n    rb_define_method(cSPKI, \"to_pem\", ossl_spki_to_pem, 0);\n    rb_define_alias(cSPKI, \"to_s\", \"to_pem\");\n    rb_define_method(cSPKI, \"to_text\", ossl_spki_print, 0);\n    rb_define_method(cSPKI, \"public_key\", ossl_spki_get_public_key, 0);\n    rb_define_method(cSPKI, \"public_key=\", ossl_spki_set_public_key, 1);\n    rb_define_method(cSPKI, \"sign\", ossl_spki_sign, 2);\n    rb_define_method(cSPKI, \"verify\", ossl_spki_verify, 1);\n    rb_define_method(cSPKI, \"challenge\", ossl_spki_get_challenge, 0);\n    rb_define_method(cSPKI, \"challenge=\", ossl_spki_set_challenge, 1);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_ns_spki.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_NS_SPKI_H_)\n#define _OSSL_NS_SPKI_H_\n\nvoid Init_ossl_ns_spki(void);\n\n#endif /* _OSSL_NS_SPKI_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_ocsp.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2003  Michal Rokos <m.rokos@sh.cvut.cz>\n * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#if !defined(OPENSSL_NO_OCSP)\n\n#define NewOCSPReq(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_ocsp_request_type, 0)\n#define SetOCSPReq(obj, req) do { \\\n    if(!(req)) ossl_raise(rb_eRuntimeError, \"Request wasn't initialized!\"); \\\n    RTYPEDDATA_DATA(obj) = (req); \\\n} while (0)\n#define GetOCSPReq(obj, req) do { \\\n    TypedData_Get_Struct((obj), OCSP_REQUEST, &ossl_ocsp_request_type, (req)); \\\n    if(!(req)) ossl_raise(rb_eRuntimeError, \"Request wasn't initialized!\"); \\\n} while (0)\n\n#define NewOCSPRes(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_ocsp_response_type, 0)\n#define SetOCSPRes(obj, res) do { \\\n    if(!(res)) ossl_raise(rb_eRuntimeError, \"Response wasn't initialized!\"); \\\n    RTYPEDDATA_DATA(obj) = (res); \\\n} while (0)\n#define GetOCSPRes(obj, res) do { \\\n    TypedData_Get_Struct((obj), OCSP_RESPONSE, &ossl_ocsp_response_type, (res)); \\\n    if(!(res)) ossl_raise(rb_eRuntimeError, \"Response wasn't initialized!\"); \\\n} while (0)\n\n#define NewOCSPBasicRes(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_ocsp_basicresp_type, 0)\n#define SetOCSPBasicRes(obj, res) do { \\\n    if(!(res)) ossl_raise(rb_eRuntimeError, \"Response wasn't initialized!\"); \\\n    RTYPEDDATA_DATA(obj) = (res); \\\n} while (0)\n#define GetOCSPBasicRes(obj, res) do { \\\n    TypedData_Get_Struct((obj), OCSP_BASICRESP, &ossl_ocsp_basicresp_type, (res)); \\\n    if(!(res)) ossl_raise(rb_eRuntimeError, \"Response wasn't initialized!\"); \\\n} while (0)\n\n#define NewOCSPSingleRes(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_ocsp_singleresp_type, 0)\n#define SetOCSPSingleRes(obj, res) do { \\\n    if(!(res)) ossl_raise(rb_eRuntimeError, \"SingleResponse wasn't initialized!\"); \\\n    RTYPEDDATA_DATA(obj) = (res); \\\n} while (0)\n#define GetOCSPSingleRes(obj, res) do { \\\n    TypedData_Get_Struct((obj), OCSP_SINGLERESP, &ossl_ocsp_singleresp_type, (res)); \\\n    if(!(res)) ossl_raise(rb_eRuntimeError, \"SingleResponse wasn't initialized!\"); \\\n} while (0)\n\n#define NewOCSPCertId(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_ocsp_certid_type, 0)\n#define SetOCSPCertId(obj, cid) do { \\\n    if(!(cid)) ossl_raise(rb_eRuntimeError, \"Cert ID wasn't initialized!\"); \\\n    RTYPEDDATA_DATA(obj) = (cid); \\\n} while (0)\n#define GetOCSPCertId(obj, cid) do { \\\n    TypedData_Get_Struct((obj), OCSP_CERTID, &ossl_ocsp_certid_type, (cid)); \\\n    if(!(cid)) ossl_raise(rb_eRuntimeError, \"Cert ID wasn't initialized!\"); \\\n} while (0)\n\nstatic VALUE mOCSP;\nstatic VALUE eOCSPError;\nstatic VALUE cOCSPReq;\nstatic VALUE cOCSPRes;\nstatic VALUE cOCSPBasicRes;\nstatic VALUE cOCSPSingleRes;\nstatic VALUE cOCSPCertId;\n\nstatic void\nossl_ocsp_request_free(void *ptr)\n{\n    OCSP_REQUEST_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ocsp_request_type = {\n    \"OpenSSL/OCSP/REQUEST\",\n    {\n        0, ossl_ocsp_request_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic void\nossl_ocsp_response_free(void *ptr)\n{\n    OCSP_RESPONSE_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ocsp_response_type = {\n    \"OpenSSL/OCSP/RESPONSE\",\n    {\n        0, ossl_ocsp_response_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic void\nossl_ocsp_basicresp_free(void *ptr)\n{\n    OCSP_BASICRESP_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ocsp_basicresp_type = {\n    \"OpenSSL/OCSP/BASICRESP\",\n    {\n        0, ossl_ocsp_basicresp_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic void\nossl_ocsp_singleresp_free(void *ptr)\n{\n    OCSP_SINGLERESP_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ocsp_singleresp_type = {\n    \"OpenSSL/OCSP/SINGLERESP\",\n    {\n        0, ossl_ocsp_singleresp_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic void\nossl_ocsp_certid_free(void *ptr)\n{\n    OCSP_CERTID_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ocsp_certid_type = {\n    \"OpenSSL/OCSP/CERTID\",\n    {\n        0, ossl_ocsp_certid_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Public\n */\nstatic VALUE\nossl_ocspcid_new(const OCSP_CERTID *cid)\n{\n    VALUE obj = NewOCSPCertId(cOCSPCertId);\n    /* OpenSSL 1.1.1 takes a non-const pointer */\n    OCSP_CERTID *cid_new = OCSP_CERTID_dup((OCSP_CERTID *)cid);\n    if (!cid_new)\n        ossl_raise(eOCSPError, \"OCSP_CERTID_dup\");\n    SetOCSPCertId(obj, cid_new);\n    return obj;\n}\n\n/*\n * OCSP::Request\n */\nstatic VALUE\nossl_ocspreq_alloc(VALUE klass)\n{\n    OCSP_REQUEST *req;\n    VALUE obj;\n\n    obj = NewOCSPReq(klass);\n    if (!(req = OCSP_REQUEST_new()))\n        ossl_raise(eOCSPError, NULL);\n    SetOCSPReq(obj, req);\n\n    return obj;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_ocspreq_initialize_copy(VALUE self, VALUE other)\n{\n    OCSP_REQUEST *req, *req_old, *req_new;\n\n    rb_check_frozen(self);\n    GetOCSPReq(self, req_old);\n    GetOCSPReq(other, req);\n\n    req_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_REQUEST), req);\n    if (!req_new)\n        ossl_raise(eOCSPError, \"ASN1_item_dup\");\n\n    SetOCSPReq(self, req_new);\n    OCSP_REQUEST_free(req_old);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   OpenSSL::OCSP::Request.new              -> request\n *   OpenSSL::OCSP::Request.new(request_der) -> request\n *\n * Creates a new OpenSSL::OCSP::Request.  The request may be created empty or\n * from a _request_der_ string.\n */\n\nstatic VALUE\nossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)\n{\n    VALUE arg;\n    OCSP_REQUEST *req, *req_new;\n    const unsigned char *p;\n\n    rb_scan_args(argc, argv, \"01\", &arg);\n    if(!NIL_P(arg)){\n        GetOCSPReq(self, req);\n        arg = ossl_to_der_if_possible(arg);\n        StringValue(arg);\n        p = (unsigned char *)RSTRING_PTR(arg);\n        req_new = d2i_OCSP_REQUEST(NULL, &p, RSTRING_LEN(arg));\n        if (!req_new)\n            ossl_raise(eOCSPError, \"d2i_OCSP_REQUEST\");\n        SetOCSPReq(self, req_new);\n        OCSP_REQUEST_free(req);\n    }\n\n    return self;\n}\n\n/*\n * call-seq:\n *   request.add_nonce(nonce = nil) -> request\n *\n * Adds a _nonce_ to the OCSP request.  If no nonce is given a random one will\n * be generated.\n *\n * The nonce is used to prevent replay attacks but some servers do not support\n * it.\n */\n\nstatic VALUE\nossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)\n{\n    OCSP_REQUEST *req;\n    VALUE val;\n    int ret;\n\n    rb_scan_args(argc, argv, \"01\", &val);\n    if(NIL_P(val)) {\n        GetOCSPReq(self, req);\n        ret = OCSP_request_add1_nonce(req, NULL, -1);\n    }\n    else{\n        StringValue(val);\n        GetOCSPReq(self, req);\n        ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));\n    }\n    if(!ret) ossl_raise(eOCSPError, NULL);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   request.check_nonce(response) -> result\n *\n * Checks the nonce validity for this request and _response_.\n *\n * The return value is one of the following:\n *\n * -1 :: nonce in request only.\n *  0 :: nonces both present and not equal.\n *  1 :: nonces present and equal.\n *  2 :: nonces both absent.\n *  3 :: nonce present in response only.\n *\n * For most responses, clients can check _result_ > 0.  If a responder doesn't\n * handle nonces <code>result.nonzero?</code> may be necessary.  A result of\n * <code>0</code> is always an error.\n */\n\nstatic VALUE\nossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp)\n{\n    OCSP_REQUEST *req;\n    OCSP_BASICRESP *bs;\n    int res;\n\n    GetOCSPReq(self, req);\n    GetOCSPBasicRes(basic_resp, bs);\n    res = OCSP_check_nonce(req, bs);\n\n    return INT2NUM(res);\n}\n\n/*\n * call-seq:\n *   request.add_certid(certificate_id) -> request\n *\n * Adds _certificate_id_ to the request.\n */\n\nstatic VALUE\nossl_ocspreq_add_certid(VALUE self, VALUE certid)\n{\n    OCSP_REQUEST *req;\n    OCSP_CERTID *id, *id_new;\n\n    GetOCSPReq(self, req);\n    GetOCSPCertId(certid, id);\n\n    if (!(id_new = OCSP_CERTID_dup(id)))\n        ossl_raise(eOCSPError, \"OCSP_CERTID_dup\");\n    if (!OCSP_request_add0_id(req, id_new)) {\n        OCSP_CERTID_free(id_new);\n        ossl_raise(eOCSPError, \"OCSP_request_add0_id\");\n    }\n\n    return self;\n}\n\n/*\n * call-seq:\n *   request.certid -> [certificate_id, ...]\n *\n * Returns all certificate IDs in this request.\n */\n\nstatic VALUE\nossl_ocspreq_get_certid(VALUE self)\n{\n    OCSP_REQUEST *req;\n\n    GetOCSPReq(self, req);\n    int count = OCSP_request_onereq_count(req);\n    if (count < 0)\n        ossl_raise(eOCSPError, \"OCSP_request_onereq_count\");\n    if (count == 0)\n        return Qnil;\n\n    VALUE ary = rb_ary_new_capa(count);\n    for (int i = 0; i < count; i++) {\n        OCSP_ONEREQ *one = OCSP_request_onereq_get0(req, i);\n        OCSP_CERTID *cid = OCSP_onereq_get0_id(one);\n        rb_ary_push(ary, ossl_ocspcid_new(cid));\n    }\n\n    return ary;\n}\n\n/*\n * call-seq:\n *   request.sign(cert, key, certs = nil, flags = 0, digest = nil) -> self\n *\n * Signs this OCSP request using _cert_, _key_ and optional _digest_. If\n * _digest_ is not specified, SHA-1 is used. _certs_ is an optional Array of\n * additional certificates which are included in the request in addition to\n * the signer certificate. Note that if _certs_ is +nil+ or not given, flag\n * OpenSSL::OCSP::NOCERTS is enabled. Pass an empty array to include only the\n * signer certificate.\n *\n * _flags_ is a bitwise OR of the following constants:\n *\n * OpenSSL::OCSP::NOCERTS::\n *   Don't include any certificates in the request. _certs_ will be ignored.\n */\nstatic VALUE\nossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)\n{\n    VALUE signer_cert, signer_key, certs, flags, digest, md_holder;\n    OCSP_REQUEST *req;\n    X509 *signer;\n    EVP_PKEY *key;\n    STACK_OF(X509) *x509s = NULL;\n    unsigned long flg = 0;\n    const EVP_MD *md;\n    int ret;\n\n    rb_scan_args(argc, argv, \"23\", &signer_cert, &signer_key, &certs, &flags, &digest);\n    GetOCSPReq(self, req);\n    signer = GetX509CertPtr(signer_cert);\n    key = GetPrivPKeyPtr(signer_key);\n    if (!NIL_P(flags))\n        flg = NUM2INT(flags);\n    md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);\n    if (NIL_P(certs))\n        flg |= OCSP_NOCERTS;\n    else\n        x509s = ossl_x509_ary2sk(certs);\n\n    ret = OCSP_request_sign(req, signer, key, md, x509s, flg);\n    sk_X509_pop_free(x509s, X509_free);\n    if (!ret)\n        ossl_raise(eOCSPError, \"OCSP_request_sign\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *   request.verify(certificates, store, flags = 0) -> true or false\n *\n * Verifies this request using the given _certificates_ and _store_.\n * _certificates_ is an array of OpenSSL::X509::Certificate, _store_ is an\n * OpenSSL::X509::Store.\n *\n * Note that +false+ is returned if the request does not have a signature.\n * Use #signed? to check whether the request is signed or not.\n */\n\nstatic VALUE\nossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)\n{\n    VALUE certs, store, flags;\n    OCSP_REQUEST *req;\n    STACK_OF(X509) *x509s;\n    X509_STORE *x509st;\n    int flg, result;\n\n    rb_scan_args(argc, argv, \"21\", &certs, &store, &flags);\n    GetOCSPReq(self, req);\n    x509st = GetX509StorePtr(store);\n    flg = NIL_P(flags) ? 0 : NUM2INT(flags);\n    x509s = ossl_x509_ary2sk(certs);\n    result = OCSP_request_verify(req, x509s, x509st, flg);\n    sk_X509_pop_free(x509s, X509_free);\n    if (result <= 0)\n        ossl_clear_error();\n\n    return result > 0 ? Qtrue : Qfalse;\n}\n\n/*\n * Returns this request as a DER-encoded string\n */\n\nstatic VALUE\nossl_ocspreq_to_der(VALUE self)\n{\n    OCSP_REQUEST *req;\n    VALUE str;\n    unsigned char *p;\n    long len;\n\n    GetOCSPReq(self, req);\n    if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d_OCSP_REQUEST(req, &p) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * call-seq:\n *    request.signed? -> true or false\n *\n * Returns +true+ if the request is signed, +false+ otherwise. Note that the\n * validity of the signature is *not* checked. Use #verify to verify that.\n */\nstatic VALUE\nossl_ocspreq_signed_p(VALUE self)\n{\n    OCSP_REQUEST *req;\n\n    GetOCSPReq(self, req);\n    return OCSP_request_is_signed(req) ? Qtrue : Qfalse;\n}\n\n/*\n * OCSP::Response\n */\n\n/* call-seq:\n *   OpenSSL::OCSP::Response.create(status, basic_response = nil) -> response\n *\n * Creates an OpenSSL::OCSP::Response from _status_ and _basic_response_.\n */\n\nstatic VALUE\nossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp)\n{\n    OCSP_BASICRESP *bs;\n    OCSP_RESPONSE *res;\n    VALUE obj;\n    int st = NUM2INT(status);\n\n    if(NIL_P(basic_resp)) bs = NULL;\n    else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */\n    obj = NewOCSPRes(klass);\n    if(!(res = OCSP_response_create(st, bs)))\n        ossl_raise(eOCSPError, NULL);\n    SetOCSPRes(obj, res);\n\n    return obj;\n}\n\nstatic VALUE\nossl_ocspres_alloc(VALUE klass)\n{\n    OCSP_RESPONSE *res;\n    VALUE obj;\n\n    obj = NewOCSPRes(klass);\n    if(!(res = OCSP_RESPONSE_new()))\n        ossl_raise(eOCSPError, NULL);\n    SetOCSPRes(obj, res);\n\n    return obj;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_ocspres_initialize_copy(VALUE self, VALUE other)\n{\n    OCSP_RESPONSE *res, *res_old, *res_new;\n\n    rb_check_frozen(self);\n    GetOCSPRes(self, res_old);\n    GetOCSPRes(other, res);\n\n    res_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_RESPONSE), res);\n    if (!res_new)\n        ossl_raise(eOCSPError, \"ASN1_item_dup\");\n\n    SetOCSPRes(self, res_new);\n    OCSP_RESPONSE_free(res_old);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   OpenSSL::OCSP::Response.new               -> response\n *   OpenSSL::OCSP::Response.new(response_der) -> response\n *\n * Creates a new OpenSSL::OCSP::Response.  The response may be created empty or\n * from a _response_der_ string.\n */\n\nstatic VALUE\nossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)\n{\n    VALUE arg;\n    OCSP_RESPONSE *res, *res_new;\n    const unsigned char *p;\n\n    rb_scan_args(argc, argv, \"01\", &arg);\n    if(!NIL_P(arg)){\n        GetOCSPRes(self, res);\n        arg = ossl_to_der_if_possible(arg);\n        StringValue(arg);\n        p = (unsigned char *)RSTRING_PTR(arg);\n        res_new = d2i_OCSP_RESPONSE(NULL, &p, RSTRING_LEN(arg));\n        if (!res_new)\n            ossl_raise(eOCSPError, \"d2i_OCSP_RESPONSE\");\n        SetOCSPRes(self, res_new);\n        OCSP_RESPONSE_free(res);\n    }\n\n    return self;\n}\n\n/*\n * call-seq:\n *   response.status -> Integer\n *\n * Returns the status of the response.\n */\n\nstatic VALUE\nossl_ocspres_status(VALUE self)\n{\n    OCSP_RESPONSE *res;\n    int st;\n\n    GetOCSPRes(self, res);\n    st = OCSP_response_status(res);\n\n    return INT2NUM(st);\n}\n\n/*\n * call-seq:\n *   response.status_string -> String\n *\n * Returns a status string for the response.\n */\n\nstatic VALUE\nossl_ocspres_status_string(VALUE self)\n{\n    OCSP_RESPONSE *res;\n    int st;\n\n    GetOCSPRes(self, res);\n    st = OCSP_response_status(res);\n\n    return rb_str_new2(OCSP_response_status_str(st));\n}\n\n/*\n * call-seq:\n *   response.basic\n *\n * Returns a BasicResponse for this response\n */\n\nstatic VALUE\nossl_ocspres_get_basic(VALUE self)\n{\n    OCSP_RESPONSE *res;\n    OCSP_BASICRESP *bs;\n    VALUE ret;\n\n    GetOCSPRes(self, res);\n    ret = NewOCSPBasicRes(cOCSPBasicRes);\n    if(!(bs = OCSP_response_get1_basic(res)))\n        return Qnil;\n    SetOCSPBasicRes(ret, bs);\n\n    return ret;\n}\n\n/*\n * call-seq:\n *   response.to_der -> String\n *\n * Returns this response as a DER-encoded string.\n */\n\nstatic VALUE\nossl_ocspres_to_der(VALUE self)\n{\n    OCSP_RESPONSE *res;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetOCSPRes(self, res);\n    if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d_OCSP_RESPONSE(res, &p) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * OCSP::BasicResponse\n */\nstatic VALUE\nossl_ocspbres_alloc(VALUE klass)\n{\n    OCSP_BASICRESP *bs;\n    VALUE obj;\n\n    obj = NewOCSPBasicRes(klass);\n    if(!(bs = OCSP_BASICRESP_new()))\n        ossl_raise(eOCSPError, NULL);\n    SetOCSPBasicRes(obj, bs);\n\n    return obj;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_ocspbres_initialize_copy(VALUE self, VALUE other)\n{\n    OCSP_BASICRESP *bs, *bs_old, *bs_new;\n\n    rb_check_frozen(self);\n    GetOCSPBasicRes(self, bs_old);\n    GetOCSPBasicRes(other, bs);\n\n    bs_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs);\n    if (!bs_new)\n        ossl_raise(eOCSPError, \"ASN1_item_dup\");\n\n    SetOCSPBasicRes(self, bs_new);\n    OCSP_BASICRESP_free(bs_old);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   OpenSSL::OCSP::BasicResponse.new(der_string = nil) -> basic_response\n *\n * Creates a new BasicResponse. If _der_string_ is given, decodes _der_string_\n * as DER.\n */\n\nstatic VALUE\nossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)\n{\n    VALUE arg;\n    OCSP_BASICRESP *res, *res_new;\n    const unsigned char *p;\n\n    rb_scan_args(argc, argv, \"01\", &arg);\n    if (!NIL_P(arg)) {\n        GetOCSPBasicRes(self, res);\n        arg = ossl_to_der_if_possible(arg);\n        StringValue(arg);\n        p = (unsigned char *)RSTRING_PTR(arg);\n        res_new = d2i_OCSP_BASICRESP(NULL, &p, RSTRING_LEN(arg));\n        if (!res_new)\n            ossl_raise(eOCSPError, \"d2i_OCSP_BASICRESP\");\n        SetOCSPBasicRes(self, res_new);\n        OCSP_BASICRESP_free(res);\n    }\n\n    return self;\n}\n\n/*\n * call-seq:\n *   basic_response.copy_nonce(request) -> Integer\n *\n * Copies the nonce from _request_ into this response.  Returns 1 on success\n * and 0 on failure.\n */\n\nstatic VALUE\nossl_ocspbres_copy_nonce(VALUE self, VALUE request)\n{\n    OCSP_BASICRESP *bs;\n    OCSP_REQUEST *req;\n    int ret;\n\n    GetOCSPBasicRes(self, bs);\n    GetOCSPReq(request, req);\n    ret = OCSP_copy_nonce(bs, req);\n\n    return INT2NUM(ret);\n}\n\n/*\n * call-seq:\n *   basic_response.add_nonce(nonce = nil)\n *\n * Adds _nonce_ to this response.  If no nonce was provided a random nonce\n * will be added.\n */\n\nstatic VALUE\nossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)\n{\n    OCSP_BASICRESP *bs;\n    VALUE val;\n    int ret;\n\n    rb_scan_args(argc, argv, \"01\", &val);\n    if(NIL_P(val)) {\n        GetOCSPBasicRes(self, bs);\n        ret = OCSP_basic_add1_nonce(bs, NULL, -1);\n    }\n    else{\n        StringValue(val);\n        GetOCSPBasicRes(self, bs);\n        ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));\n    }\n    if(!ret) ossl_raise(eOCSPError, NULL);\n\n    return self;\n}\n\nstatic VALUE\nadd_status_convert_time(VALUE obj)\n{\n    ASN1_TIME *time;\n\n    if (RB_INTEGER_TYPE_P(obj))\n        time = X509_gmtime_adj(NULL, NUM2INT(obj));\n    else\n        time = ossl_x509_time_adjust(NULL, obj);\n\n    if (!time)\n        ossl_raise(eOCSPError, NULL);\n\n    return (VALUE)time;\n}\n\n/*\n * call-seq:\n *   basic_response.add_status(certificate_id, status, reason, revocation_time, this_update, next_update, extensions) -> basic_response\n *\n * Adds a certificate status for _certificate_id_. _status_ is the status, and\n * must be one of these:\n *\n * - OpenSSL::OCSP::V_CERTSTATUS_GOOD\n * - OpenSSL::OCSP::V_CERTSTATUS_REVOKED\n * - OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN\n *\n * _reason_ and _revocation_time_ can be given only when _status_ is\n * OpenSSL::OCSP::V_CERTSTATUS_REVOKED. _reason_ describes the reason for the\n * revocation, and must be one of OpenSSL::OCSP::REVOKED_STATUS_* constants.\n * _revocation_time_ is the time when the certificate is revoked.\n *\n * _this_update_ and _next_update_ indicate the time at which the status is\n * verified to be correct and the time at or before which newer information\n * will be available, respectively. _next_update_ is optional.\n *\n * _extensions_ is an Array of OpenSSL::X509::Extension to be included in the\n * SingleResponse. This is also optional.\n *\n * Note that the times, _revocation_time_, _this_update_ and _next_update_\n * can be specified in either of Integer or Time object. If they are Integer, it\n * is treated as the relative seconds from the current time.\n */\nstatic VALUE\nossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,\n                         VALUE reason, VALUE revtime,\n                         VALUE thisupd, VALUE nextupd, VALUE ext)\n{\n    OCSP_BASICRESP *bs;\n    OCSP_SINGLERESP *single;\n    OCSP_CERTID *id;\n    ASN1_TIME *ths = NULL, *nxt = NULL, *rev = NULL;\n    int st, rsn = 0, error = 0, rstatus = 0;\n    long i;\n    VALUE tmp;\n\n    GetOCSPBasicRes(self, bs);\n    GetOCSPCertId(cid, id);\n    st = NUM2INT(status);\n    if (!NIL_P(ext)) { /* All ext's members must be X509::Extension */\n        ext = rb_check_array_type(ext);\n        for (i = 0; i < RARRAY_LEN(ext); i++)\n            OSSL_Check_Kind(RARRAY_AREF(ext, i), cX509Ext);\n    }\n\n    if (st == V_OCSP_CERTSTATUS_REVOKED) {\n        rsn = NUM2INT(reason);\n        tmp = rb_protect(add_status_convert_time, revtime, &rstatus);\n        if (rstatus) goto err;\n        rev = (ASN1_TIME *)tmp;\n    }\n\n    tmp = rb_protect(add_status_convert_time, thisupd, &rstatus);\n    if (rstatus) goto err;\n    ths = (ASN1_TIME *)tmp;\n\n    if (!NIL_P(nextupd)) {\n        tmp = rb_protect(add_status_convert_time, nextupd, &rstatus);\n        if (rstatus) goto err;\n        nxt = (ASN1_TIME *)tmp;\n    }\n\n    if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){\n        error = 1;\n        goto err;\n    }\n\n    if(!NIL_P(ext)){\n        X509_EXTENSION *x509ext;\n\n        for(i = 0; i < RARRAY_LEN(ext); i++){\n            x509ext = GetX509ExtPtr(RARRAY_AREF(ext, i));\n            if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){\n                error = 1;\n                goto err;\n            }\n        }\n    }\n\n  err:\n    ASN1_TIME_free(ths);\n    ASN1_TIME_free(nxt);\n    ASN1_TIME_free(rev);\n    if(error) ossl_raise(eOCSPError, NULL);\n    if(rstatus) rb_jump_tag(rstatus);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   basic_response.status -> statuses\n *\n * Returns an Array of statuses for this response.  Each status contains a\n * CertificateId, the status (0 for good, 1 for revoked, 2 for unknown), the\n * reason for the status, the revocation time, the time of this update, the time\n * for the next update and a list of OpenSSL::X509::Extension.\n *\n * This should be superseded by BasicResponse#responses and #find_response that\n * return SingleResponse.\n */\nstatic VALUE\nossl_ocspbres_get_status(VALUE self)\n{\n    OCSP_BASICRESP *bs;\n\n    GetOCSPBasicRes(self, bs);\n    VALUE ret = rb_ary_new();\n    int count = OCSP_resp_count(bs);\n    for (int i = 0; i < count; i++) {\n        OCSP_SINGLERESP *single = OCSP_resp_get0(bs, i);\n        ASN1_TIME *revtime = NULL, *thisupd = NULL, *nextupd = NULL;\n        int reason = -1;\n\n        int status = OCSP_single_get0_status(single, &reason, &revtime, &thisupd, &nextupd);\n        if (status < 0)\n            ossl_raise(eOCSPError, \"OCSP_single_get0_status\");\n\n        VALUE ary = rb_ary_new();\n        rb_ary_push(ary, ossl_ocspcid_new(OCSP_SINGLERESP_get0_id(single)));\n        rb_ary_push(ary, INT2NUM(status));\n        rb_ary_push(ary, INT2NUM(reason));\n        rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);\n        rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);\n        rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);\n        VALUE ext = rb_ary_new();\n        int ext_count = OCSP_SINGLERESP_get_ext_count(single);\n        for (int j = 0; j < ext_count; j++) {\n            const X509_EXTENSION *x509ext = OCSP_SINGLERESP_get_ext(single, j);\n            rb_ary_push(ext, ossl_x509ext_new(x509ext));\n        }\n        rb_ary_push(ary, ext);\n        rb_ary_push(ret, ary);\n    }\n\n    return ret;\n}\n\nstatic VALUE ossl_ocspsres_new(const OCSP_SINGLERESP *);\n\n/*\n * call-seq:\n *   basic_response.responses -> Array of SingleResponse\n *\n * Returns an Array of SingleResponse for this BasicResponse.\n */\n\nstatic VALUE\nossl_ocspbres_get_responses(VALUE self)\n{\n    OCSP_BASICRESP *bs;\n    VALUE ret;\n    int count, i;\n\n    GetOCSPBasicRes(self, bs);\n    count = OCSP_resp_count(bs);\n    ret = rb_ary_new_capa(count);\n\n    for (i = 0; i < count; i++) {\n        rb_ary_push(ret, ossl_ocspsres_new(OCSP_resp_get0(bs, i)));\n    }\n\n    return ret;\n}\n\n\n/*\n * call-seq:\n *   basic_response.find_response(certificate_id) -> SingleResponse | nil\n *\n * Returns a SingleResponse whose CertId matches with _certificate_id_, or +nil+\n * if this BasicResponse does not contain it.\n */\nstatic VALUE\nossl_ocspbres_find_response(VALUE self, VALUE target)\n{\n    OCSP_BASICRESP *bs;\n    OCSP_CERTID *id;\n    int n;\n\n    GetOCSPCertId(target, id);\n    GetOCSPBasicRes(self, bs);\n\n    if ((n = OCSP_resp_find(bs, id, -1)) == -1)\n        return Qnil;\n    return ossl_ocspsres_new(OCSP_resp_get0(bs, n));\n}\n\n/*\n * call-seq:\n *   basic_response.sign(cert, key, certs = nil, flags = 0, digest = nil) -> self\n *\n * Signs this OCSP response using the _cert_, _key_ and optional _digest_. This\n * behaves in the similar way as OpenSSL::OCSP::Request#sign.\n *\n * _flags_ can include:\n * OpenSSL::OCSP::NOCERTS::    don't include certificates\n * OpenSSL::OCSP::NOTIME::     don't set producedAt\n * OpenSSL::OCSP::RESPID_KEY:: use signer's public key hash as responderID\n */\n\nstatic VALUE\nossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)\n{\n    VALUE signer_cert, signer_key, certs, flags, digest, md_holder;\n    OCSP_BASICRESP *bs;\n    X509 *signer;\n    EVP_PKEY *key;\n    STACK_OF(X509) *x509s = NULL;\n    unsigned long flg = 0;\n    const EVP_MD *md;\n    int ret;\n\n    rb_scan_args(argc, argv, \"23\", &signer_cert, &signer_key, &certs, &flags, &digest);\n    GetOCSPBasicRes(self, bs);\n    signer = GetX509CertPtr(signer_cert);\n    key = GetPrivPKeyPtr(signer_key);\n    if (!NIL_P(flags))\n        flg = NUM2INT(flags);\n    md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);\n    if (NIL_P(certs))\n        flg |= OCSP_NOCERTS;\n    else\n        x509s = ossl_x509_ary2sk(certs);\n\n    ret = OCSP_basic_sign(bs, signer, key, md, x509s, flg);\n    sk_X509_pop_free(x509s, X509_free);\n    if (!ret)\n        ossl_raise(eOCSPError, \"OCSP_basic_sign\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *   basic_response.verify(certificates, store, flags = 0) -> true or false\n *\n * Verifies the signature of the response using the given _certificates_ and\n * _store_. This works in the similar way as OpenSSL::OCSP::Request#verify.\n */\nstatic VALUE\nossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)\n{\n    VALUE certs, store, flags;\n    OCSP_BASICRESP *bs;\n    STACK_OF(X509) *x509s;\n    X509_STORE *x509st;\n    int flg, result;\n\n    rb_scan_args(argc, argv, \"21\", &certs, &store, &flags);\n    GetOCSPBasicRes(self, bs);\n    x509st = GetX509StorePtr(store);\n    flg = NIL_P(flags) ? 0 : NUM2INT(flags);\n    x509s = ossl_x509_ary2sk(certs);\n    result = OCSP_basic_verify(bs, x509s, x509st, flg);\n    sk_X509_pop_free(x509s, X509_free);\n    if (result <= 0)\n        ossl_clear_error();\n\n    return result > 0 ? Qtrue : Qfalse;\n}\n\n/*\n * call-seq:\n *   basic_response.to_der -> String\n *\n * Encodes this basic response into a DER-encoded string.\n */\nstatic VALUE\nossl_ocspbres_to_der(VALUE self)\n{\n    OCSP_BASICRESP *res;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetOCSPBasicRes(self, res);\n    if ((len = i2d_OCSP_BASICRESP(res, NULL)) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_OCSP_BASICRESP(res, &p) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * OCSP::SingleResponse\n */\nstatic VALUE\nossl_ocspsres_new(const OCSP_SINGLERESP *sres)\n{\n    VALUE obj;\n    OCSP_SINGLERESP *sres_new;\n\n    obj = NewOCSPSingleRes(cOCSPSingleRes);\n    /* OpenSSL 1.1.1 takes a non-const pointer */\n    sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP),\n                             (OCSP_SINGLERESP *)sres);\n    if (!sres_new)\n        ossl_raise(eOCSPError, \"ASN1_item_dup\");\n    SetOCSPSingleRes(obj, sres_new);\n\n    return obj;\n}\n\nstatic VALUE\nossl_ocspsres_alloc(VALUE klass)\n{\n    OCSP_SINGLERESP *sres;\n    VALUE obj;\n\n    obj = NewOCSPSingleRes(klass);\n    if (!(sres = OCSP_SINGLERESP_new()))\n        ossl_raise(eOCSPError, NULL);\n    SetOCSPSingleRes(obj, sres);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *   OpenSSL::OCSP::SingleResponse.new(der_string) -> SingleResponse\n *\n * Creates a new SingleResponse from _der_string_.\n */\nstatic VALUE\nossl_ocspsres_initialize(VALUE self, VALUE arg)\n{\n    OCSP_SINGLERESP *res, *res_new;\n    const unsigned char *p;\n\n    arg = ossl_to_der_if_possible(arg);\n    StringValue(arg);\n    GetOCSPSingleRes(self, res);\n\n    p = (unsigned char*)RSTRING_PTR(arg);\n    res_new = d2i_OCSP_SINGLERESP(NULL, &p, RSTRING_LEN(arg));\n    if (!res_new)\n        ossl_raise(eOCSPError, \"d2i_OCSP_SINGLERESP\");\n    SetOCSPSingleRes(self, res_new);\n    OCSP_SINGLERESP_free(res);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_ocspsres_initialize_copy(VALUE self, VALUE other)\n{\n    OCSP_SINGLERESP *sres, *sres_old, *sres_new;\n\n    rb_check_frozen(self);\n    GetOCSPSingleRes(self, sres_old);\n    GetOCSPSingleRes(other, sres);\n\n    sres_new = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_SINGLERESP), sres);\n    if (!sres_new)\n        ossl_raise(eOCSPError, \"ASN1_item_dup\");\n\n    SetOCSPSingleRes(self, sres_new);\n    OCSP_SINGLERESP_free(sres_old);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   single_response.check_validity(nsec = 0, maxsec = -1) -> true | false\n *\n * Checks the validity of thisUpdate and nextUpdate fields of this\n * SingleResponse. This checks the current time is within the range thisUpdate\n * to nextUpdate.\n *\n * It is possible that the OCSP request takes a few seconds or the time is not\n * accurate. To avoid rejecting a valid response, this method allows the times\n * to be within _nsec_ seconds of the current time.\n *\n * Some responders don't set the nextUpdate field. This may cause a very old\n * response to be considered valid. The _maxsec_ parameter can be used to limit\n * the age of responses.\n */\nstatic VALUE\nossl_ocspsres_check_validity(int argc, VALUE *argv, VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n    ASN1_GENERALIZEDTIME *this_update, *next_update;\n    VALUE nsec_v, maxsec_v;\n    int nsec, maxsec, status, ret;\n\n    rb_scan_args(argc, argv, \"02\", &nsec_v, &maxsec_v);\n    nsec = NIL_P(nsec_v) ? 0 : NUM2INT(nsec_v);\n    maxsec = NIL_P(maxsec_v) ? -1 : NUM2INT(maxsec_v);\n\n    GetOCSPSingleRes(self, sres);\n    status = OCSP_single_get0_status(sres, NULL, NULL, &this_update, &next_update);\n    if (status < 0)\n        ossl_raise(eOCSPError, \"OCSP_single_get0_status\");\n\n    ret = OCSP_check_validity(this_update, next_update, nsec, maxsec);\n\n    if (ret)\n        return Qtrue;\n    else {\n        ossl_clear_error();\n        return Qfalse;\n    }\n}\n\n/*\n * call-seq:\n *   single_response.certid -> CertificateId\n *\n * Returns the CertificateId for which this SingleResponse is.\n */\nstatic VALUE\nossl_ocspsres_get_certid(VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n\n    GetOCSPSingleRes(self, sres);\n    return ossl_ocspcid_new(OCSP_SINGLERESP_get0_id(sres));\n}\n\n/*\n * call-seq:\n *   single_response.cert_status -> Integer\n *\n * Returns the status of the certificate identified by the certid.\n * The return value may be one of these constant:\n *\n * - V_CERTSTATUS_GOOD\n * - V_CERTSTATUS_REVOKED\n * - V_CERTSTATUS_UNKNOWN\n *\n * When the status is V_CERTSTATUS_REVOKED, the time at which the certificate\n * was revoked can be retrieved by #revocation_time.\n */\nstatic VALUE\nossl_ocspsres_get_cert_status(VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n    int status;\n\n    GetOCSPSingleRes(self, sres);\n    status = OCSP_single_get0_status(sres, NULL, NULL, NULL, NULL);\n    if (status < 0)\n        ossl_raise(eOCSPError, \"OCSP_single_get0_status\");\n\n    return INT2NUM(status);\n}\n\n/*\n * call-seq:\n *   single_response.this_update -> Time\n */\nstatic VALUE\nossl_ocspsres_get_this_update(VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n    int status;\n    ASN1_GENERALIZEDTIME *time;\n\n    GetOCSPSingleRes(self, sres);\n    status = OCSP_single_get0_status(sres, NULL, NULL, &time, NULL);\n    if (status < 0)\n        ossl_raise(eOCSPError, \"OCSP_single_get0_status\");\n    if (!time)\n        return Qnil;\n\n    return asn1time_to_time(time);\n}\n\n/*\n * call-seq:\n *   single_response.next_update -> Time | nil\n */\nstatic VALUE\nossl_ocspsres_get_next_update(VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n    int status;\n    ASN1_GENERALIZEDTIME *time;\n\n    GetOCSPSingleRes(self, sres);\n    status = OCSP_single_get0_status(sres, NULL, NULL, NULL, &time);\n    if (status < 0)\n        ossl_raise(eOCSPError, \"OCSP_single_get0_status\");\n    if (!time)\n        return Qnil;\n\n    return asn1time_to_time(time);\n}\n\n/*\n * call-seq:\n *   single_response.revocation_time -> Time | nil\n */\nstatic VALUE\nossl_ocspsres_get_revocation_time(VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n    int status;\n    ASN1_GENERALIZEDTIME *time;\n\n    GetOCSPSingleRes(self, sres);\n    status = OCSP_single_get0_status(sres, NULL, &time, NULL, NULL);\n    if (status < 0)\n        ossl_raise(eOCSPError, \"OCSP_single_get0_status\");\n    if (status != V_OCSP_CERTSTATUS_REVOKED)\n        ossl_raise(eOCSPError, \"certificate is not revoked\");\n    if (!time)\n        return Qnil;\n\n    return asn1time_to_time(time);\n}\n\n/*\n * call-seq:\n *   single_response.revocation_reason -> Integer | nil\n */\nstatic VALUE\nossl_ocspsres_get_revocation_reason(VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n    int status, reason;\n\n    GetOCSPSingleRes(self, sres);\n    status = OCSP_single_get0_status(sres, &reason, NULL, NULL, NULL);\n    if (status < 0)\n        ossl_raise(eOCSPError, \"OCSP_single_get0_status\");\n    if (status != V_OCSP_CERTSTATUS_REVOKED)\n        ossl_raise(eOCSPError, \"certificate is not revoked\");\n\n    return INT2NUM(reason);\n}\n\n/*\n * call-seq:\n *   single_response.extensions -> Array of X509::Extension\n */\nstatic VALUE\nossl_ocspsres_get_extensions(VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n    int count, i;\n    VALUE ary;\n\n    GetOCSPSingleRes(self, sres);\n\n    count = OCSP_SINGLERESP_get_ext_count(sres);\n    ary = rb_ary_new2(count);\n    for (i = 0; i < count; i++) {\n        const X509_EXTENSION *ext = OCSP_SINGLERESP_get_ext(sres, i);\n        rb_ary_push(ary, ossl_x509ext_new(ext)); /* will dup */\n    }\n\n    return ary;\n}\n\n/*\n * call-seq:\n *   single_response.to_der -> String\n *\n * Encodes this SingleResponse into a DER-encoded string.\n */\nstatic VALUE\nossl_ocspsres_to_der(VALUE self)\n{\n    OCSP_SINGLERESP *sres;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetOCSPSingleRes(self, sres);\n    if ((len = i2d_OCSP_SINGLERESP(sres, NULL)) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_OCSP_SINGLERESP(sres, &p) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n\n/*\n * OCSP::CertificateId\n */\nstatic VALUE\nossl_ocspcid_alloc(VALUE klass)\n{\n    OCSP_CERTID *id;\n    VALUE obj;\n\n    obj = NewOCSPCertId(klass);\n    if(!(id = OCSP_CERTID_new()))\n        ossl_raise(eOCSPError, NULL);\n    SetOCSPCertId(obj, id);\n\n    return obj;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_ocspcid_initialize_copy(VALUE self, VALUE other)\n{\n    OCSP_CERTID *cid, *cid_old, *cid_new;\n\n    rb_check_frozen(self);\n    GetOCSPCertId(self, cid_old);\n    GetOCSPCertId(other, cid);\n\n    cid_new = OCSP_CERTID_dup(cid);\n    if (!cid_new)\n        ossl_raise(eOCSPError, \"OCSP_CERTID_dup\");\n\n    SetOCSPCertId(self, cid_new);\n    OCSP_CERTID_free(cid_old);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   OpenSSL::OCSP::CertificateId.new(subject, issuer, digest = nil) -> certificate_id\n *   OpenSSL::OCSP::CertificateId.new(der_string)                    -> certificate_id\n *   OpenSSL::OCSP::CertificateId.new(obj)                           -> certificate_id\n *\n * Creates a new OpenSSL::OCSP::CertificateId for the given _subject_ and\n * _issuer_ X509 certificates.  The _digest_ is a digest algorithm that is used\n * to compute the hash values. This defaults to SHA-1.\n *\n * If only one argument is given, decodes it as DER representation of a\n * certificate ID or generates certificate ID from the object that responds to\n * the to_der method.\n */\nstatic VALUE\nossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)\n{\n    OCSP_CERTID *id, *newid;\n    VALUE subject, issuer, digest;\n\n    GetOCSPCertId(self, id);\n    if (rb_scan_args(argc, argv, \"12\", &subject, &issuer, &digest) == 1) {\n        VALUE arg;\n        const unsigned char *p;\n\n        arg = ossl_to_der_if_possible(subject);\n        StringValue(arg);\n        p = (unsigned char *)RSTRING_PTR(arg);\n        newid = d2i_OCSP_CERTID(NULL, &p, RSTRING_LEN(arg));\n        if (!newid)\n            ossl_raise(eOCSPError, \"d2i_OCSP_CERTID\");\n    }\n    else {\n        X509 *x509s, *x509i;\n        const EVP_MD *md;\n        VALUE md_holder;\n\n        x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */\n        x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */\n        md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);\n\n        newid = OCSP_cert_to_id(md, x509s, x509i);\n        if (!newid)\n            ossl_raise(eOCSPError, \"OCSP_cert_to_id\");\n    }\n\n    SetOCSPCertId(self, newid);\n    OCSP_CERTID_free(id);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   certificate_id.cmp(other) -> true or false\n *\n * Compares this certificate id with _other_ and returns +true+ if they are the\n * same.\n */\nstatic VALUE\nossl_ocspcid_cmp(VALUE self, VALUE other)\n{\n    OCSP_CERTID *id, *id2;\n    int result;\n\n    GetOCSPCertId(self, id);\n    GetOCSPCertId(other, id2);\n    result = OCSP_id_cmp(id, id2);\n\n    return (result == 0) ? Qtrue : Qfalse;\n}\n\n/*\n * call-seq:\n *   certificate_id.cmp_issuer(other) -> true or false\n *\n * Compares this certificate id's issuer with _other_ and returns +true+ if\n * they are the same.\n */\n\nstatic VALUE\nossl_ocspcid_cmp_issuer(VALUE self, VALUE other)\n{\n    OCSP_CERTID *id, *id2;\n    int result;\n\n    GetOCSPCertId(self, id);\n    GetOCSPCertId(other, id2);\n    result = OCSP_id_issuer_cmp(id, id2);\n\n    return (result == 0) ? Qtrue : Qfalse;\n}\n\n/*\n * call-seq:\n *   certificate_id.serial -> Integer\n *\n * Returns the serial number of the certificate for which status is being\n * requested.\n */\nstatic VALUE\nossl_ocspcid_get_serial(VALUE self)\n{\n    OCSP_CERTID *id;\n    ASN1_INTEGER *serial;\n\n    GetOCSPCertId(self, id);\n    OCSP_id_get0_info(NULL, NULL, NULL, &serial, id);\n\n    return asn1integer_to_num(serial);\n}\n\n/*\n * call-seq:\n *   certificate_id.issuer_name_hash -> String\n *\n * Returns the issuerNameHash of this certificate ID, the hash of the\n * issuer's distinguished name calculated with the hashAlgorithm.\n */\nstatic VALUE\nossl_ocspcid_get_issuer_name_hash(VALUE self)\n{\n    OCSP_CERTID *id;\n    ASN1_OCTET_STRING *name_hash;\n    VALUE ret;\n\n    GetOCSPCertId(self, id);\n    OCSP_id_get0_info(&name_hash, NULL, NULL, NULL, id);\n\n    ret = rb_str_new(NULL, ASN1_STRING_length(name_hash) * 2);\n    ossl_bin2hex(ASN1_STRING_get0_data(name_hash), RSTRING_PTR(ret),\n                 ASN1_STRING_length(name_hash));\n\n    return ret;\n}\n\n/*\n * call-seq:\n *   certificate_id.issuer_key_hash -> String\n *\n * Returns the issuerKeyHash of this certificate ID, the hash of the issuer's\n * public key.\n */\nstatic VALUE\nossl_ocspcid_get_issuer_key_hash(VALUE self)\n{\n    OCSP_CERTID *id;\n    ASN1_OCTET_STRING *key_hash;\n    VALUE ret;\n\n    GetOCSPCertId(self, id);\n    OCSP_id_get0_info(NULL, NULL, &key_hash, NULL, id);\n\n    ret = rb_str_new(NULL, ASN1_STRING_length(key_hash) * 2);\n    ossl_bin2hex(ASN1_STRING_get0_data(key_hash), RSTRING_PTR(ret),\n                 ASN1_STRING_length(key_hash));\n\n    return ret;\n}\n\n/*\n * call-seq:\n *   certificate_id.hash_algorithm -> String\n *\n * Returns the ln (long name) of the hash algorithm used to generate\n * the issuerNameHash and the issuerKeyHash values.\n */\nstatic VALUE\nossl_ocspcid_get_hash_algorithm(VALUE self)\n{\n    OCSP_CERTID *id;\n    ASN1_OBJECT *oid;\n\n    GetOCSPCertId(self, id);\n    OCSP_id_get0_info(NULL, &oid, NULL, NULL, id);\n    return ossl_asn1obj_to_string_long_name(oid);\n}\n\n/*\n * call-seq:\n *   certificate_id.to_der -> String\n *\n * Encodes this certificate identifier into a DER-encoded string.\n */\nstatic VALUE\nossl_ocspcid_to_der(VALUE self)\n{\n    OCSP_CERTID *id;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetOCSPCertId(self, id);\n    if ((len = i2d_OCSP_CERTID(id, NULL)) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_OCSP_CERTID(id, &p) <= 0)\n        ossl_raise(eOCSPError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\nvoid\nInit_ossl_ocsp(void)\n{\n    /*\n     * OpenSSL::OCSP implements Online Certificate Status Protocol requests\n     * and responses.\n     *\n     * Creating and sending an OCSP request requires a subject certificate\n     * that contains an OCSP URL in an authorityInfoAccess extension and the\n     * issuer certificate for the subject certificate.  First, load the issuer\n     * and subject certificates:\n     *\n     *   subject = OpenSSL::X509::Certificate.new subject_pem\n     *   issuer  = OpenSSL::X509::Certificate.new issuer_pem\n     *\n     * To create the request we need to create a certificate ID for the\n     * subject certificate so the CA knows which certificate we are asking\n     * about:\n     *\n     *   digest = OpenSSL::Digest.new('SHA1')\n     *   certificate_id =\n     *     OpenSSL::OCSP::CertificateId.new subject, issuer, digest\n     *\n     * Then create a request and add the certificate ID to it:\n     *\n     *   request = OpenSSL::OCSP::Request.new\n     *   request.add_certid certificate_id\n     *\n     * Adding a nonce to the request protects against replay attacks but not\n     * all CA process the nonce.\n     *\n     *   request.add_nonce\n     *\n     * To submit the request to the CA for verification we need to extract the\n     * OCSP URI from the subject certificate:\n     *\n     *   ocsp_uris = subject.ocsp_uris\n     *\n     *   require 'uri'\n     *\n     *   ocsp_uri = URI ocsp_uris[0]\n     *\n     * To submit the request we'll POST the request to the OCSP URI (per RFC\n     * 2560).  Note that we only handle HTTP requests and don't handle any\n     * redirects in this example, so this is insufficient for serious use.\n     *\n     *   require 'net/http'\n     *\n     *   http_response =\n     *     Net::HTTP.start ocsp_uri.hostname, ocsp_uri.port do |http|\n     *       http.post ocsp_uri.path, request.to_der,\n     *                 'content-type' => 'application/ocsp-request'\n     *   end\n     *\n     *   response = OpenSSL::OCSP::Response.new http_response.body\n     *   response_basic = response.basic\n     *\n     * First we check if the response has a valid signature.  Without a valid\n     * signature we cannot trust it.  If you get a failure here you may be\n     * missing a system certificate store or may be missing the intermediate\n     * certificates.\n     *\n     *   store = OpenSSL::X509::Store.new\n     *   store.set_default_paths\n     *\n     *   unless response_basic.verify [], store then\n     *     raise 'response is not signed by a trusted certificate'\n     *   end\n     *\n     * The response contains the status information (success/fail).  We can\n     * display the status as a string:\n     *\n     *   puts response.status_string #=> successful\n     *\n     * Next we need to know the response details to determine if the response\n     * matches our request.  First we check the nonce.  Again, not all CAs\n     * support a nonce.  See Request#check_nonce for the meanings of the\n     * return values.\n     *\n     *   p request.check_nonce basic_response #=> value from -1 to 3\n     *\n     * Then extract the status information for the certificate from the basic\n     * response.\n     *\n     *   single_response = basic_response.find_response(certificate_id)\n     *\n     *   unless single_response\n     *     raise 'basic_response does not have the status for the certificate'\n     *   end\n     *\n     * Then check the validity. A status issued in the future must be rejected.\n     *\n     *   unless single_response.check_validity\n     *     raise 'this_update is in the future or next_update time has passed'\n     *   end\n     *\n     *   case single_response.cert_status\n     *   when OpenSSL::OCSP::V_CERTSTATUS_GOOD\n     *     puts 'certificate is still valid'\n     *   when OpenSSL::OCSP::V_CERTSTATUS_REVOKED\n     *     puts \"certificate has been revoked at #{single_response.revocation_time}\"\n     *   when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN\n     *     puts 'responder doesn't know about the certificate'\n     *   end\n     */\n\n    mOCSP = rb_define_module_under(mOSSL, \"OCSP\");\n\n    /*\n     * OCSP error class.\n     */\n\n    eOCSPError = rb_define_class_under(mOCSP, \"OCSPError\", eOSSLError);\n\n    /*\n     * An OpenSSL::OCSP::Request contains the certificate information for\n     * determining if a certificate has been revoked or not.  A Request can be\n     * created for a certificate or from a DER-encoded request created\n     * elsewhere.\n     */\n\n    cOCSPReq = rb_define_class_under(mOCSP, \"Request\", rb_cObject);\n    rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc);\n    rb_define_method(cOCSPReq, \"initialize_copy\", ossl_ocspreq_initialize_copy, 1);\n    rb_define_method(cOCSPReq, \"initialize\", ossl_ocspreq_initialize, -1);\n    rb_define_method(cOCSPReq, \"add_nonce\", ossl_ocspreq_add_nonce, -1);\n    rb_define_method(cOCSPReq, \"check_nonce\", ossl_ocspreq_check_nonce, 1);\n    rb_define_method(cOCSPReq, \"add_certid\", ossl_ocspreq_add_certid, 1);\n    rb_define_method(cOCSPReq, \"certid\", ossl_ocspreq_get_certid, 0);\n    rb_define_method(cOCSPReq, \"signed?\", ossl_ocspreq_signed_p, 0);\n    rb_define_method(cOCSPReq, \"sign\", ossl_ocspreq_sign, -1);\n    rb_define_method(cOCSPReq, \"verify\", ossl_ocspreq_verify, -1);\n    rb_define_method(cOCSPReq, \"to_der\", ossl_ocspreq_to_der, 0);\n\n    /*\n     * An OpenSSL::OCSP::Response contains the status of a certificate check\n     * which is created from an OpenSSL::OCSP::Request.\n     */\n\n    cOCSPRes = rb_define_class_under(mOCSP, \"Response\", rb_cObject);\n    rb_define_singleton_method(cOCSPRes, \"create\", ossl_ocspres_s_create, 2);\n    rb_define_alloc_func(cOCSPRes, ossl_ocspres_alloc);\n    rb_define_method(cOCSPRes, \"initialize_copy\", ossl_ocspres_initialize_copy, 1);\n    rb_define_method(cOCSPRes, \"initialize\", ossl_ocspres_initialize, -1);\n    rb_define_method(cOCSPRes, \"status\", ossl_ocspres_status, 0);\n    rb_define_method(cOCSPRes, \"status_string\", ossl_ocspres_status_string, 0);\n    rb_define_method(cOCSPRes, \"basic\", ossl_ocspres_get_basic, 0);\n    rb_define_method(cOCSPRes, \"to_der\", ossl_ocspres_to_der, 0);\n\n    /*\n     * An OpenSSL::OCSP::BasicResponse contains the status of a certificate\n     * check which is created from an OpenSSL::OCSP::Request.  A\n     * BasicResponse is more detailed than a Response.\n     */\n\n    cOCSPBasicRes = rb_define_class_under(mOCSP, \"BasicResponse\", rb_cObject);\n    rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc);\n    rb_define_method(cOCSPBasicRes, \"initialize_copy\", ossl_ocspbres_initialize_copy, 1);\n    rb_define_method(cOCSPBasicRes, \"initialize\", ossl_ocspbres_initialize, -1);\n    rb_define_method(cOCSPBasicRes, \"copy_nonce\", ossl_ocspbres_copy_nonce, 1);\n    rb_define_method(cOCSPBasicRes, \"add_nonce\", ossl_ocspbres_add_nonce, -1);\n    rb_define_method(cOCSPBasicRes, \"add_status\", ossl_ocspbres_add_status, 7);\n    rb_define_method(cOCSPBasicRes, \"status\", ossl_ocspbres_get_status, 0);\n    rb_define_method(cOCSPBasicRes, \"responses\", ossl_ocspbres_get_responses, 0);\n    rb_define_method(cOCSPBasicRes, \"find_response\", ossl_ocspbres_find_response, 1);\n    rb_define_method(cOCSPBasicRes, \"sign\", ossl_ocspbres_sign, -1);\n    rb_define_method(cOCSPBasicRes, \"verify\", ossl_ocspbres_verify, -1);\n    rb_define_method(cOCSPBasicRes, \"to_der\", ossl_ocspbres_to_der, 0);\n\n    /*\n     * An OpenSSL::OCSP::SingleResponse represents an OCSP SingleResponse\n     * structure, which contains the basic information of the status of the\n     * certificate.\n     */\n    cOCSPSingleRes = rb_define_class_under(mOCSP, \"SingleResponse\", rb_cObject);\n    rb_define_alloc_func(cOCSPSingleRes, ossl_ocspsres_alloc);\n    rb_define_method(cOCSPSingleRes, \"initialize_copy\", ossl_ocspsres_initialize_copy, 1);\n    rb_define_method(cOCSPSingleRes, \"initialize\", ossl_ocspsres_initialize, 1);\n    rb_define_method(cOCSPSingleRes, \"check_validity\", ossl_ocspsres_check_validity, -1);\n    rb_define_method(cOCSPSingleRes, \"certid\", ossl_ocspsres_get_certid, 0);\n    rb_define_method(cOCSPSingleRes, \"cert_status\", ossl_ocspsres_get_cert_status, 0);\n    rb_define_method(cOCSPSingleRes, \"this_update\", ossl_ocspsres_get_this_update, 0);\n    rb_define_method(cOCSPSingleRes, \"next_update\", ossl_ocspsres_get_next_update, 0);\n    rb_define_method(cOCSPSingleRes, \"revocation_time\", ossl_ocspsres_get_revocation_time, 0);\n    rb_define_method(cOCSPSingleRes, \"revocation_reason\", ossl_ocspsres_get_revocation_reason, 0);\n    rb_define_method(cOCSPSingleRes, \"extensions\", ossl_ocspsres_get_extensions, 0);\n    rb_define_method(cOCSPSingleRes, \"to_der\", ossl_ocspsres_to_der, 0);\n\n    /*\n     * An OpenSSL::OCSP::CertificateId identifies a certificate to the CA so\n     * that a status check can be performed.\n     */\n\n    cOCSPCertId = rb_define_class_under(mOCSP, \"CertificateId\", rb_cObject);\n    rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc);\n    rb_define_method(cOCSPCertId, \"initialize_copy\", ossl_ocspcid_initialize_copy, 1);\n    rb_define_method(cOCSPCertId, \"initialize\", ossl_ocspcid_initialize, -1);\n    rb_define_method(cOCSPCertId, \"cmp\", ossl_ocspcid_cmp, 1);\n    rb_define_method(cOCSPCertId, \"cmp_issuer\", ossl_ocspcid_cmp_issuer, 1);\n    rb_define_method(cOCSPCertId, \"serial\", ossl_ocspcid_get_serial, 0);\n    rb_define_method(cOCSPCertId, \"issuer_name_hash\", ossl_ocspcid_get_issuer_name_hash, 0);\n    rb_define_method(cOCSPCertId, \"issuer_key_hash\", ossl_ocspcid_get_issuer_key_hash, 0);\n    rb_define_method(cOCSPCertId, \"hash_algorithm\", ossl_ocspcid_get_hash_algorithm, 0);\n    rb_define_method(cOCSPCertId, \"to_der\", ossl_ocspcid_to_der, 0);\n\n    /* Internal error in issuer */\n    rb_define_const(mOCSP, \"RESPONSE_STATUS_INTERNALERROR\", INT2NUM(OCSP_RESPONSE_STATUS_INTERNALERROR));\n\n    /* Illegal confirmation request */\n    rb_define_const(mOCSP, \"RESPONSE_STATUS_MALFORMEDREQUEST\", INT2NUM(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST));\n\n    /* The certificate was revoked for an unknown reason */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_NOSTATUS\", INT2NUM(OCSP_REVOKED_STATUS_NOSTATUS));\n\n    /* You must sign the request and resubmit */\n    rb_define_const(mOCSP, \"RESPONSE_STATUS_SIGREQUIRED\", INT2NUM(OCSP_RESPONSE_STATUS_SIGREQUIRED));\n\n    /* Response has valid confirmations */\n    rb_define_const(mOCSP, \"RESPONSE_STATUS_SUCCESSFUL\", INT2NUM(OCSP_RESPONSE_STATUS_SUCCESSFUL));\n\n    /* Try again later */\n    rb_define_const(mOCSP, \"RESPONSE_STATUS_TRYLATER\", INT2NUM(OCSP_RESPONSE_STATUS_TRYLATER));\n\n    /* The certificate subject's name or other information changed */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_AFFILIATIONCHANGED\", INT2NUM(OCSP_REVOKED_STATUS_AFFILIATIONCHANGED));\n\n    /* This CA certificate was revoked due to a key compromise */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_CACOMPROMISE\", INT2NUM(OCSP_REVOKED_STATUS_CACOMPROMISE));\n\n    /* The certificate is on hold */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_CERTIFICATEHOLD\", INT2NUM(OCSP_REVOKED_STATUS_CERTIFICATEHOLD));\n\n    /* The certificate is no longer needed */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_CESSATIONOFOPERATION\", INT2NUM(OCSP_REVOKED_STATUS_CESSATIONOFOPERATION));\n\n    /* The certificate was revoked due to a key compromise */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_KEYCOMPROMISE\", INT2NUM(OCSP_REVOKED_STATUS_KEYCOMPROMISE));\n\n    /* The certificate was previously on hold and should now be removed from\n     * the CRL */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_REMOVEFROMCRL\", INT2NUM(OCSP_REVOKED_STATUS_REMOVEFROMCRL));\n\n    /* The certificate was superseded by a new certificate */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_SUPERSEDED\", INT2NUM(OCSP_REVOKED_STATUS_SUPERSEDED));\n\n    /* Your request is unauthorized. */\n    rb_define_const(mOCSP, \"RESPONSE_STATUS_UNAUTHORIZED\", INT2NUM(OCSP_RESPONSE_STATUS_UNAUTHORIZED));\n\n    /* The certificate was revoked for an unspecified reason */\n    rb_define_const(mOCSP, \"REVOKED_STATUS_UNSPECIFIED\", INT2NUM(OCSP_REVOKED_STATUS_UNSPECIFIED));\n\n    /* Do not include certificates in the response */\n    rb_define_const(mOCSP, \"NOCERTS\", INT2NUM(OCSP_NOCERTS));\n\n    /* Do not search certificates contained in the response for a signer */\n    rb_define_const(mOCSP, \"NOINTERN\", INT2NUM(OCSP_NOINTERN));\n\n    /* Do not check the signature on the response */\n    rb_define_const(mOCSP, \"NOSIGS\", INT2NUM(OCSP_NOSIGS));\n\n    /* Do not verify the certificate chain on the response */\n    rb_define_const(mOCSP, \"NOCHAIN\", INT2NUM(OCSP_NOCHAIN));\n\n    /* Do not verify the response at all */\n    rb_define_const(mOCSP, \"NOVERIFY\", INT2NUM(OCSP_NOVERIFY));\n\n    /* Do not check trust */\n    rb_define_const(mOCSP, \"NOEXPLICIT\", INT2NUM(OCSP_NOEXPLICIT));\n\n    /* (This flag is not used by OpenSSL 1.0.1g) */\n    rb_define_const(mOCSP, \"NOCASIGN\", INT2NUM(OCSP_NOCASIGN));\n\n    /* (This flag is not used by OpenSSL 1.0.1g) */\n    rb_define_const(mOCSP, \"NODELEGATED\", INT2NUM(OCSP_NODELEGATED));\n\n    /* Do not make additional signing certificate checks */\n    rb_define_const(mOCSP, \"NOCHECKS\", INT2NUM(OCSP_NOCHECKS));\n\n    /* Do not verify additional certificates */\n    rb_define_const(mOCSP, \"TRUSTOTHER\", INT2NUM(OCSP_TRUSTOTHER));\n\n    /* Identify the response by signing the certificate key ID */\n    rb_define_const(mOCSP, \"RESPID_KEY\", INT2NUM(OCSP_RESPID_KEY));\n\n    /* Do not include producedAt time in response */\n    rb_define_const(mOCSP, \"NOTIME\", INT2NUM(OCSP_NOTIME));\n\n    /* Indicates the certificate is not revoked but does not necessarily mean\n     * the certificate was issued or that this response is within the\n     * certificate's validity interval */\n    rb_define_const(mOCSP, \"V_CERTSTATUS_GOOD\", INT2NUM(V_OCSP_CERTSTATUS_GOOD));\n    /* Indicates the certificate has been revoked either permanently or\n     * temporarily (on hold). */\n    rb_define_const(mOCSP, \"V_CERTSTATUS_REVOKED\", INT2NUM(V_OCSP_CERTSTATUS_REVOKED));\n\n    /* Indicates the responder does not know about the certificate being\n     * requested. */\n    rb_define_const(mOCSP, \"V_CERTSTATUS_UNKNOWN\", INT2NUM(V_OCSP_CERTSTATUS_UNKNOWN));\n\n    /* The responder ID is based on the key name. */\n    rb_define_const(mOCSP, \"V_RESPID_NAME\", INT2NUM(V_OCSP_RESPID_NAME));\n\n    /* The responder ID is based on the public key. */\n    rb_define_const(mOCSP, \"V_RESPID_KEY\", INT2NUM(V_OCSP_RESPID_KEY));\n}\n#else\nvoid\nInit_ossl_ocsp(void)\n{\n}\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_ocsp.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2003  Michal Rokos <m.rokos@sh.cvut.cz>\n * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_OCSP_H_)\n#define _OSSL_OCSP_H_\n\nvoid Init_ossl_ocsp(void);\n\n#endif /* _OSSL_OCSP_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_pkcs12.c",
    "content": "/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewPKCS12(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_pkcs12_type, 0)\n\n#define SetPKCS12(obj, p12) do { \\\n    if(!(p12)) ossl_raise(rb_eRuntimeError, \"PKCS12 wasn't initialized.\"); \\\n    RTYPEDDATA_DATA(obj) = (p12); \\\n} while (0)\n\n#define GetPKCS12(obj, p12) do { \\\n    TypedData_Get_Struct((obj), PKCS12, &ossl_pkcs12_type, (p12)); \\\n    if(!(p12)) ossl_raise(rb_eRuntimeError, \"PKCS12 wasn't initialized.\"); \\\n} while (0)\n\n#define ossl_pkcs12_set_key(o,v)      rb_iv_set((o), \"@key\", (v))\n#define ossl_pkcs12_set_cert(o,v)     rb_iv_set((o), \"@certificate\", (v))\n#define ossl_pkcs12_set_ca_certs(o,v) rb_iv_set((o), \"@ca_certs\", (v))\n#define ossl_pkcs12_get_key(o)        rb_iv_get((o), \"@key\")\n#define ossl_pkcs12_get_cert(o)       rb_iv_get((o), \"@certificate\")\n#define ossl_pkcs12_get_ca_certs(o)   rb_iv_get((o), \"@ca_certs\")\n\n/*\n * Classes\n */\nstatic VALUE cPKCS12;\nstatic VALUE ePKCS12Error;\n\n/*\n * Private\n */\nstatic void\nossl_pkcs12_free(void *ptr)\n{\n    PKCS12_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_pkcs12_type = {\n    \"OpenSSL/PKCS12\",\n    {\n        0, ossl_pkcs12_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_pkcs12_s_allocate(VALUE klass)\n{\n    PKCS12 *p12;\n    VALUE obj;\n\n    obj = NewPKCS12(klass);\n    if(!(p12 = PKCS12_new())) ossl_raise(ePKCS12Error, NULL);\n    SetPKCS12(obj, p12);\n\n    return obj;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_pkcs12_initialize_copy(VALUE self, VALUE other)\n{\n    PKCS12 *p12, *p12_old, *p12_new;\n\n    rb_check_frozen(self);\n    GetPKCS12(self, p12_old);\n    GetPKCS12(other, p12);\n\n    p12_new = ASN1_dup((i2d_of_void *)i2d_PKCS12, (d2i_of_void *)d2i_PKCS12, (char *)p12);\n    if (!p12_new)\n        ossl_raise(ePKCS12Error, \"ASN1_dup\");\n\n    SetPKCS12(self, p12_new);\n    PKCS12_free(p12_old);\n\n    return self;\n}\n\n/*\n * call-seq:\n *    PKCS12.create(pass, name, key, cert [, ca, [, key_pbe [, cert_pbe [, key_iter [, mac_iter [, keytype]]]]]])\n *\n * === Parameters\n * * _pass_ - string\n * * _name_ - A string describing the key.\n * * _key_ - Any PKey.\n * * _cert_ - A X509::Certificate.\n *   * The public_key portion of the certificate must contain a valid public key.\n *   * The not_before and not_after fields must be filled in.\n * * _ca_ - An optional array of X509::Certificate's.\n * * _key_pbe_ - string\n * * _cert_pbe_ - string\n * * _key_iter_ - integer\n * * _mac_iter_ - integer\n * * _keytype_ - An integer representing an MSIE specific extension.\n *\n * Any optional arguments may be supplied as +nil+ to preserve the OpenSSL defaults.\n *\n * See the OpenSSL documentation for PKCS12_create().\n */\nstatic VALUE\nossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)\n{\n    VALUE pass, name, pkey, cert, ca, key_nid, cert_nid, key_iter, mac_iter, keytype;\n    VALUE obj;\n    char *passphrase, *friendlyname;\n    EVP_PKEY *key;\n    X509 *x509;\n    STACK_OF(X509) *x509s;\n    int nkey = 0, ncert = 0, kiter = 0, miter = 0, ktype = 0;\n    PKCS12 *p12;\n\n    rb_scan_args(argc, argv, \"46\", &pass, &name, &pkey, &cert, &ca, &key_nid, &cert_nid, &key_iter, &mac_iter, &keytype);\n    passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass);\n    friendlyname = NIL_P(name) ? NULL : StringValueCStr(name);\n    key = GetPKeyPtr(pkey);\n    x509 = GetX509CertPtr(cert);\n/* TODO: make a VALUE to nid function */\n    if (!NIL_P(key_nid)) {\n        if ((nkey = OBJ_txt2nid(StringValueCStr(key_nid))) == NID_undef)\n            ossl_raise(rb_eArgError, \"Unknown PBE algorithm %\"PRIsVALUE, key_nid);\n    }\n    if (!NIL_P(cert_nid)) {\n        if ((ncert = OBJ_txt2nid(StringValueCStr(cert_nid))) == NID_undef)\n            ossl_raise(rb_eArgError, \"Unknown PBE algorithm %\"PRIsVALUE, cert_nid);\n    }\n    if (!NIL_P(key_iter))\n        kiter = NUM2INT(key_iter);\n    if (!NIL_P(mac_iter))\n        miter = NUM2INT(mac_iter);\n    if (!NIL_P(keytype))\n        ktype = NUM2INT(keytype);\n\n#if defined(OPENSSL_IS_AWSLC)\n    if (ktype != 0) {\n        ossl_raise(rb_eArgError, \"Unknown key usage type %\"PRIsVALUE, INT2NUM(ktype));\n    }\n#else\n    if (ktype != 0 && ktype != KEY_SIG && ktype != KEY_EX) {\n        ossl_raise(rb_eArgError, \"Unknown key usage type %\"PRIsVALUE, INT2NUM(ktype));\n    }\n#endif\n\n    obj = NewPKCS12(cPKCS12);\n    x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca);\n    p12 = PKCS12_create(passphrase, friendlyname, key, x509, x509s,\n                        nkey, ncert, kiter, miter, ktype);\n    sk_X509_pop_free(x509s, X509_free);\n    if(!p12) ossl_raise(ePKCS12Error, NULL);\n    SetPKCS12(obj, p12);\n\n    ossl_pkcs12_set_key(obj, pkey);\n    ossl_pkcs12_set_cert(obj, cert);\n    ossl_pkcs12_set_ca_certs(obj, ca);\n\n    return obj;\n}\n\nstatic VALUE\nossl_pkey_wrap_i(VALUE arg)\n{\n    return ossl_pkey_wrap((EVP_PKEY *)arg);\n}\n\nstatic VALUE\nossl_x509_new_i(VALUE arg)\n{\n    return ossl_x509_new((X509 *)arg);\n}\n\nstatic VALUE\nossl_x509_sk2ary_i(VALUE arg)\n{\n    return ossl_x509_sk2ary((STACK_OF(X509) *)arg);\n}\n\n/*\n * call-seq:\n *    PKCS12.new -> pkcs12\n *    PKCS12.new(str) -> pkcs12\n *    PKCS12.new(str, pass) -> pkcs12\n *\n * === Parameters\n * * _str_ - Must be a DER encoded PKCS12 string.\n * * _pass_ - string\n */\nstatic VALUE\nossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)\n{\n    BIO *in;\n    VALUE arg, pass, pkey, cert, ca;\n    char *passphrase;\n    EVP_PKEY *key;\n    X509 *x509;\n    STACK_OF(X509) *x509s = NULL;\n    int st = 0;\n    PKCS12 *pkcs = DATA_PTR(self);\n\n    if(rb_scan_args(argc, argv, \"02\", &arg, &pass) == 0) return self;\n    passphrase = NIL_P(pass) ? NULL : StringValueCStr(pass);\n    in = ossl_obj2bio(&arg);\n    d2i_PKCS12_bio(in, &pkcs);\n    DATA_PTR(self) = pkcs;\n    BIO_free(in);\n\n    pkey = cert = ca = Qnil;\n    if(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s))\n        ossl_raise(ePKCS12Error, \"PKCS12_parse\");\n    if (key) {\n        pkey = rb_protect(ossl_pkey_wrap_i, (VALUE)key, &st);\n        if (st) goto err;\n    }\n    if (x509) {\n        cert = rb_protect(ossl_x509_new_i, (VALUE)x509, &st);\n        if (st) goto err;\n    }\n    if (x509s) {\n        ca = rb_protect(ossl_x509_sk2ary_i, (VALUE)x509s, &st);\n        if (st) goto err;\n    }\n\n  err:\n    X509_free(x509);\n    sk_X509_pop_free(x509s, X509_free);\n    ossl_pkcs12_set_key(self, pkey);\n    ossl_pkcs12_set_cert(self, cert);\n    ossl_pkcs12_set_ca_certs(self, ca);\n    if(st) rb_jump_tag(st);\n\n    return self;\n}\n\nstatic VALUE\nossl_pkcs12_to_der(VALUE self)\n{\n    PKCS12 *p12;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetPKCS12(self, p12);\n    if((len = i2d_PKCS12(p12, NULL)) <= 0)\n        ossl_raise(ePKCS12Error, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d_PKCS12(p12, &p) <= 0)\n        ossl_raise(ePKCS12Error, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * call-seq:\n *    pkcs12.set_mac(pass, salt = nil, iter = nil, md_type = nil)\n *\n * Sets MAC parameters and generates MAC over the PKCS #12 structure.\n *\n * This method uses HMAC and the PKCS #12 specific password-based KDF as\n * specified in the original PKCS #12.\n *\n * See also the man page PKCS12_set_mac(3).\n *\n * Added in version 3.3.0.\n */\nstatic VALUE\npkcs12_set_mac(int argc, VALUE *argv, VALUE self)\n{\n    PKCS12 *p12;\n    VALUE pass, salt, iter, md_name, md_holder = Qnil;\n    int iter_i = 0;\n    const EVP_MD *md_type = NULL;\n\n    rb_scan_args(argc, argv, \"13\", &pass, &salt, &iter, &md_name);\n    rb_check_frozen(self);\n    GetPKCS12(self, p12);\n\n    StringValue(pass);\n    if (!NIL_P(salt))\n        StringValue(salt);\n    if (!NIL_P(iter))\n        iter_i = NUM2INT(iter);\n    if (!NIL_P(md_name))\n        md_type = ossl_evp_md_fetch(md_name, &md_holder);\n\n    if (!PKCS12_set_mac(p12, RSTRING_PTR(pass), RSTRING_LENINT(pass),\n                        !NIL_P(salt) ? (unsigned char *)RSTRING_PTR(salt) : NULL,\n                        !NIL_P(salt) ? RSTRING_LENINT(salt) : 0,\n                        iter_i, md_type))\n        ossl_raise(ePKCS12Error, \"PKCS12_set_mac\");\n\n    return Qnil;\n}\n\nvoid\nInit_ossl_pkcs12(void)\n{\n#undef rb_intern\n    /*\n     * Defines a file format commonly used to store private keys with\n     * accompanying public key certificates, protected with a password-based\n     * symmetric key.\n     */\n    cPKCS12 = rb_define_class_under(mOSSL, \"PKCS12\", rb_cObject);\n    ePKCS12Error = rb_define_class_under(cPKCS12, \"PKCS12Error\", eOSSLError);\n    rb_define_singleton_method(cPKCS12, \"create\", ossl_pkcs12_s_create, -1);\n\n    rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate);\n    rb_define_method(cPKCS12, \"initialize_copy\", ossl_pkcs12_initialize_copy, 1);\n    rb_attr(cPKCS12, rb_intern(\"key\"), 1, 0, Qfalse);\n    rb_attr(cPKCS12, rb_intern(\"certificate\"), 1, 0, Qfalse);\n    rb_attr(cPKCS12, rb_intern(\"ca_certs\"), 1, 0, Qfalse);\n    rb_define_method(cPKCS12, \"initialize\", ossl_pkcs12_initialize, -1);\n    rb_define_method(cPKCS12, \"to_der\", ossl_pkcs12_to_der, 0);\n    rb_define_method(cPKCS12, \"set_mac\", pkcs12_set_mac, -1);\n\n#if !defined(OPENSSL_IS_AWSLC)\n    /* MSIE specific PKCS12 key usage extensions */\n    rb_define_const(cPKCS12, \"KEY_EX\", INT2NUM(KEY_EX));\n    rb_define_const(cPKCS12, \"KEY_SIG\", INT2NUM(KEY_SIG));\n#endif\n}\n"
  },
  {
    "path": "ext/openssl/ossl_pkcs12.h",
    "content": "/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_PKCS12_H_)\n#define _OSSL_PKCS12_H_\n\nvoid Init_ossl_pkcs12(void);\n\n#endif /* _OSSL_PKCS12_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_pkcs7.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewPKCS7(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_pkcs7_type, 0)\n#define SetPKCS7(obj, pkcs7) do { \\\n    if (!(pkcs7)) { \\\n        ossl_raise(rb_eRuntimeError, \"PKCS7 wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (pkcs7); \\\n} while (0)\n#define GetPKCS7(obj, pkcs7) do { \\\n    TypedData_Get_Struct((obj), PKCS7, &ossl_pkcs7_type, (pkcs7)); \\\n    if (!(pkcs7)) { \\\n        ossl_raise(rb_eRuntimeError, \"PKCS7 wasn't initialized.\"); \\\n    } \\\n} while (0)\n\n#define NewPKCS7si(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_pkcs7_signer_info_type, 0)\n#define SetPKCS7si(obj, p7si) do { \\\n    if (!(p7si)) { \\\n        ossl_raise(rb_eRuntimeError, \"PKCS7si wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (p7si); \\\n} while (0)\n#define GetPKCS7si(obj, p7si) do { \\\n    TypedData_Get_Struct((obj), PKCS7_SIGNER_INFO, &ossl_pkcs7_signer_info_type, (p7si)); \\\n    if (!(p7si)) { \\\n        ossl_raise(rb_eRuntimeError, \"PKCS7si wasn't initialized.\"); \\\n    } \\\n} while (0)\n\n#define NewPKCS7ri(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_pkcs7_recip_info_type, 0)\n#define SetPKCS7ri(obj, p7ri) do { \\\n    if (!(p7ri)) { \\\n        ossl_raise(rb_eRuntimeError, \"PKCS7ri wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (p7ri); \\\n} while (0)\n#define GetPKCS7ri(obj, p7ri) do { \\\n    TypedData_Get_Struct((obj), PKCS7_RECIP_INFO, &ossl_pkcs7_recip_info_type, (p7ri)); \\\n    if (!(p7ri)) { \\\n        ossl_raise(rb_eRuntimeError, \"PKCS7ri wasn't initialized.\"); \\\n    } \\\n} while (0)\n\n#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))\n\n#define ossl_pkcs7_set_data(o,v)       rb_iv_set((o), \"@data\", (v))\n#define ossl_pkcs7_get_data(o)         rb_iv_get((o), \"@data\")\n#define ossl_pkcs7_set_err_string(o,v) rb_iv_set((o), \"@error_string\", (v))\n#define ossl_pkcs7_get_err_string(o)   rb_iv_get((o), \"@error_string\")\n\n/*\n * Classes\n */\nstatic VALUE cPKCS7;\nstatic VALUE cPKCS7Signer;\nstatic VALUE cPKCS7Recipient;\nstatic VALUE ePKCS7Error;\nstatic ID id_md_holder, id_cipher_holder;\n\nstatic void\nossl_pkcs7_free(void *ptr)\n{\n    PKCS7_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_pkcs7_type = {\n    \"OpenSSL/PKCS7\",\n    {\n        0, ossl_pkcs7_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nVALUE\nossl_pkcs7_new(PKCS7 *p7)\n{\n    PKCS7 *new;\n    VALUE obj = NewPKCS7(cPKCS7);\n\n    new = PKCS7_dup(p7);\n    if (!new)\n        ossl_raise(ePKCS7Error, \"PKCS7_dup\");\n    SetPKCS7(obj, new);\n\n    return obj;\n}\n\nstatic void\nossl_pkcs7_signer_info_free(void *ptr)\n{\n    PKCS7_SIGNER_INFO_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_pkcs7_signer_info_type = {\n    \"OpenSSL/PKCS7/SIGNER_INFO\",\n    {\n        0, ossl_pkcs7_signer_info_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic void\nossl_pkcs7_recip_info_free(void *ptr)\n{\n    PKCS7_RECIP_INFO_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_pkcs7_recip_info_type = {\n    \"OpenSSL/PKCS7/RECIP_INFO\",\n    {\n        0, ossl_pkcs7_recip_info_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Public\n * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM)\n */\nstatic PKCS7_SIGNER_INFO *\nossl_PKCS7_SIGNER_INFO_dup(PKCS7_SIGNER_INFO *si)\n{\n    PKCS7_SIGNER_INFO *si_new = ASN1_dup((i2d_of_void *)i2d_PKCS7_SIGNER_INFO,\n                                         (d2i_of_void *)d2i_PKCS7_SIGNER_INFO,\n                                         si);\n    if (si_new && si->pkey) {\n        EVP_PKEY_up_ref(si->pkey);\n        si_new->pkey = si->pkey;\n    }\n    return si_new;\n}\n\nstatic PKCS7_RECIP_INFO *\nossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *ri)\n{\n    PKCS7_RECIP_INFO *ri_new = ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,\n                                        (d2i_of_void *)d2i_PKCS7_RECIP_INFO,\n                                        ri);\n    if (ri_new && ri->cert) {\n        if (!X509_up_ref(ri->cert)) {\n            PKCS7_RECIP_INFO_free(ri_new);\n            return NULL;\n        }\n        ri_new->cert = ri->cert;\n    }\n    return ri_new;\n}\n\nstatic VALUE\nossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)\n{\n    PKCS7_SIGNER_INFO *p7si_new;\n    VALUE obj;\n\n    obj = NewPKCS7si(cPKCS7Signer);\n    p7si_new = ossl_PKCS7_SIGNER_INFO_dup(p7si);\n    if (!p7si_new)\n        ossl_raise(ePKCS7Error, \"ASN1_dup\");\n    SetPKCS7si(obj, p7si_new);\n\n    return obj;\n}\n\nstatic VALUE\nossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri)\n{\n    PKCS7_RECIP_INFO *p7ri_new;\n    VALUE obj;\n\n    obj = NewPKCS7ri(cPKCS7Recipient);\n    p7ri_new = ossl_PKCS7_RECIP_INFO_dup(p7ri);\n    if (!p7ri_new)\n        ossl_raise(ePKCS7Error,\"ASN1_dup\");\n    SetPKCS7ri(obj, p7ri_new);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    PKCS7.read_smime(string) => pkcs7\n */\nstatic VALUE\nossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)\n{\n    BIO *in, *out;\n    PKCS7 *pkcs7;\n    VALUE ret, data;\n\n    ret = NewPKCS7(cPKCS7);\n    in = ossl_obj2bio(&arg);\n    out = NULL;\n    pkcs7 = SMIME_read_PKCS7(in, &out);\n    BIO_free(in);\n    if (!pkcs7)\n        ossl_raise(ePKCS7Error, \"Could not parse the PKCS7\");\n    if (!pkcs7->d.ptr) {\n        PKCS7_free(pkcs7);\n        ossl_raise(ePKCS7Error, \"No content in PKCS7\");\n    }\n\n    data = out ? ossl_membio2str(out) : Qnil;\n    SetPKCS7(ret, pkcs7);\n    ossl_pkcs7_set_data(ret, data);\n    ossl_pkcs7_set_err_string(ret, Qnil);\n\n    return ret;\n}\n\n/*\n * call-seq:\n *    PKCS7.write_smime(pkcs7 [, data [, flags]]) => string\n */\nstatic VALUE\nossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)\n{\n    VALUE pkcs7, data, flags;\n    BIO *out, *in;\n    PKCS7 *p7;\n    VALUE str;\n    int flg;\n\n    rb_scan_args(argc, argv, \"12\", &pkcs7, &data, &flags);\n    flg = NIL_P(flags) ? 0 : NUM2INT(flags);\n    if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7);\n    GetPKCS7(pkcs7, p7);\n    if(!NIL_P(data) && PKCS7_is_detached(p7))\n        flg |= PKCS7_DETACHED;\n    in = NIL_P(data) ? NULL : ossl_obj2bio(&data);\n    if(!(out = BIO_new(BIO_s_mem()))){\n        BIO_free(in);\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    if(!SMIME_write_PKCS7(out, p7, in, flg)){\n        BIO_free(out);\n        BIO_free(in);\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    BIO_free(in);\n    str = ossl_membio2str(out);\n\n    return str;\n}\n\n/*\n * call-seq:\n *    PKCS7.sign(cert, key, data, [, certs [, flags]]) => pkcs7\n */\nstatic VALUE\nossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)\n{\n    VALUE cert, key, data, certs, flags;\n    X509 *x509;\n    EVP_PKEY *pkey;\n    BIO *in;\n    STACK_OF(X509) *x509s;\n    int flg, status = 0;\n    PKCS7 *pkcs7;\n    VALUE ret;\n\n    rb_scan_args(argc, argv, \"32\", &cert, &key, &data, &certs, &flags);\n    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */\n    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */\n    flg = NIL_P(flags) ? 0 : NUM2INT(flags);\n    ret = NewPKCS7(cPKCS7);\n    in = ossl_obj2bio(&data);\n    if(NIL_P(certs)) x509s = NULL;\n    else{\n        x509s = ossl_protect_x509_ary2sk(certs, &status);\n        if(status){\n            BIO_free(in);\n            rb_jump_tag(status);\n        }\n    }\n    if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){\n        BIO_free(in);\n        sk_X509_pop_free(x509s, X509_free);\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    SetPKCS7(ret, pkcs7);\n    ossl_pkcs7_set_data(ret, data);\n    ossl_pkcs7_set_err_string(ret, Qnil);\n    BIO_free(in);\n    sk_X509_pop_free(x509s, X509_free);\n\n    return ret;\n}\n\n/*\n * call-seq:\n *    PKCS7.encrypt(certs, data, cipher, flags = 0) => pkcs7\n *\n * Creates a PKCS #7 enveloped-data structure.\n *\n * Before version 3.3.0, +cipher+ was optional and defaulted to\n * <tt>\"RC2-40-CBC\"</tt>.\n *\n * See also the man page PKCS7_encrypt(3).\n */\nstatic VALUE\nossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)\n{\n    VALUE certs, data, cipher, flags, cipher_holder;\n    STACK_OF(X509) *x509s;\n    BIO *in;\n    const EVP_CIPHER *ciph;\n    int flg, status = 0;\n    VALUE ret;\n    PKCS7 *p7;\n\n    rb_scan_args(argc, argv, \"22\", &certs, &data, &cipher, &flags);\n    if (NIL_P(cipher)) {\n        rb_raise(rb_eArgError,\n                 \"cipher must be specified. Before version 3.3, \" \\\n                 \"the default cipher was RC2-40-CBC.\");\n    }\n    ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder);\n    flg = NIL_P(flags) ? 0 : NUM2INT(flags);\n    ret = NewPKCS7(cPKCS7);\n    in = ossl_obj2bio(&data);\n    x509s = ossl_protect_x509_ary2sk(certs, &status);\n    if(status){\n        BIO_free(in);\n        rb_jump_tag(status);\n    }\n    if (!(p7 = PKCS7_encrypt(x509s, in, ciph, flg))) {\n        BIO_free(in);\n        sk_X509_pop_free(x509s, X509_free);\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    BIO_free(in);\n    SetPKCS7(ret, p7);\n    ossl_pkcs7_set_data(ret, data);\n    rb_ivar_set(ret, id_cipher_holder, cipher_holder);\n    sk_X509_pop_free(x509s, X509_free);\n\n    return ret;\n}\n\nstatic VALUE\nossl_pkcs7_alloc(VALUE klass)\n{\n    PKCS7 *pkcs7;\n    VALUE obj;\n\n    obj = NewPKCS7(klass);\n    if (!(pkcs7 = PKCS7_new())) {\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    SetPKCS7(obj, pkcs7);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    PKCS7.new => pkcs7\n *    PKCS7.new(string) => pkcs7\n *\n * Many methods in this class aren't documented.\n */\nstatic VALUE\nossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)\n{\n    PKCS7 *p7, *p7_orig = RTYPEDDATA_DATA(self);\n    BIO *in;\n    VALUE arg;\n\n    if(rb_scan_args(argc, argv, \"01\", &arg) == 0)\n        return self;\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n    p7 = d2i_PKCS7_bio(in, NULL);\n    if (!p7) {\n        OSSL_BIO_reset(in);\n        p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);\n    }\n    BIO_free(in);\n    if (!p7)\n        ossl_raise(ePKCS7Error, \"Could not parse the PKCS7\");\n    if (!p7->d.ptr) {\n        PKCS7_free(p7);\n        ossl_raise(ePKCS7Error, \"No content in PKCS7\");\n    }\n\n    RTYPEDDATA_DATA(self) = p7;\n    PKCS7_free(p7_orig);\n    ossl_pkcs7_set_data(self, Qnil);\n    ossl_pkcs7_set_err_string(self, Qnil);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_pkcs7_copy(VALUE self, VALUE other)\n{\n    PKCS7 *a, *b, *pkcs7;\n\n    rb_check_frozen(self);\n    if (self == other) return self;\n\n    GetPKCS7(self, a);\n    GetPKCS7(other, b);\n\n    pkcs7 = PKCS7_dup(b);\n    if (!pkcs7) {\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    DATA_PTR(self) = pkcs7;\n    PKCS7_free(a);\n\n    return self;\n}\n\nstatic int\nossl_pkcs7_sym2typeid(VALUE sym)\n{\n    int i, ret = Qnil;\n    const char *s;\n    size_t l;\n\n    static const struct {\n        char name[20];\n        int nid;\n    } p7_type_tab[] = {\n        { \"signed\",             NID_pkcs7_signed },\n        { \"data\",               NID_pkcs7_data },\n        { \"signedAndEnveloped\", NID_pkcs7_signedAndEnveloped },\n        { \"enveloped\",          NID_pkcs7_enveloped },\n        { \"encrypted\",          NID_pkcs7_encrypted },\n        { \"digest\",             NID_pkcs7_digest },\n    };\n\n    if (SYMBOL_P(sym)) sym = rb_sym2str(sym);\n    else StringValue(sym);\n    RSTRING_GETMEM(sym, s, l);\n\n    for(i = 0; ; i++){\n        if(i == numberof(p7_type_tab))\n            ossl_raise(ePKCS7Error, \"unknown type \\\"%\"PRIsVALUE\"\\\"\", sym);\n        if(strlen(p7_type_tab[i].name) != l) continue;\n        if(strcmp(p7_type_tab[i].name, s) == 0){\n            ret = p7_type_tab[i].nid;\n            break;\n        }\n    }\n\n    return ret;\n}\n\n/*\n * call-seq:\n *    pkcs7.type = type => type\n */\nstatic VALUE\nossl_pkcs7_set_type(VALUE self, VALUE type)\n{\n    PKCS7 *p7;\n\n    GetPKCS7(self, p7);\n    if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type)))\n        ossl_raise(ePKCS7Error, NULL);\n\n    return type;\n}\n\n/*\n * call-seq:\n *    pkcs7.type => string or nil\n */\nstatic VALUE\nossl_pkcs7_get_type(VALUE self)\n{\n    PKCS7 *p7;\n\n    GetPKCS7(self, p7);\n    if(PKCS7_type_is_signed(p7))\n        return ID2SYM(rb_intern(\"signed\"));\n    if(PKCS7_type_is_encrypted(p7))\n        return ID2SYM(rb_intern(\"encrypted\"));\n    if(PKCS7_type_is_enveloped(p7))\n        return ID2SYM(rb_intern(\"enveloped\"));\n    if(PKCS7_type_is_signedAndEnveloped(p7))\n        return ID2SYM(rb_intern(\"signedAndEnveloped\"));\n    if(PKCS7_type_is_data(p7))\n        return ID2SYM(rb_intern(\"data\"));\n    return Qnil;\n}\n\nstatic VALUE\nossl_pkcs7_set_detached(VALUE self, VALUE flag)\n{\n    PKCS7 *p7;\n\n    GetPKCS7(self, p7);\n    if(flag != Qtrue && flag != Qfalse)\n        ossl_raise(ePKCS7Error, \"must specify a boolean\");\n    if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0))\n        ossl_raise(ePKCS7Error, NULL);\n\n    return flag;\n}\n\nstatic VALUE\nossl_pkcs7_get_detached(VALUE self)\n{\n    PKCS7 *p7;\n    GetPKCS7(self, p7);\n    if (!PKCS7_type_is_signed(p7))\n        return Qfalse;\n    return PKCS7_get_detached(p7) ? Qtrue : Qfalse;\n}\n\nstatic VALUE\nossl_pkcs7_detached_p(VALUE self)\n{\n    PKCS7 *p7;\n    GetPKCS7(self, p7);\n    return PKCS7_is_detached(p7) ? Qtrue : Qfalse;\n}\n\nstatic VALUE\nossl_pkcs7_set_cipher(VALUE self, VALUE cipher)\n{\n    PKCS7 *pkcs7;\n    const EVP_CIPHER *ciph;\n    VALUE cipher_holder;\n\n    GetPKCS7(self, pkcs7);\n    ciph = ossl_evp_cipher_fetch(cipher, &cipher_holder);\n    if (!PKCS7_set_cipher(pkcs7, ciph))\n        ossl_raise(ePKCS7Error, \"PKCS7_set_cipher\");\n    rb_ivar_set(self, id_cipher_holder, cipher_holder);\n\n    return cipher;\n}\n\nstatic VALUE\nossl_pkcs7_add_signer(VALUE self, VALUE signer)\n{\n    PKCS7 *pkcs7;\n    PKCS7_SIGNER_INFO *si, *si_new;\n\n    GetPKCS7(self, pkcs7);\n    GetPKCS7si(signer, si);\n\n    si_new = ossl_PKCS7_SIGNER_INFO_dup(si);\n    if (!si_new)\n        ossl_raise(ePKCS7Error, \"PKCS7_SIGNER_INFO_dup\");\n\n    if (PKCS7_add_signer(pkcs7, si_new) != 1) {\n        PKCS7_SIGNER_INFO_free(si_new);\n        ossl_raise(ePKCS7Error, \"PKCS7_add_signer\");\n    }\n\n    return self;\n}\n\nstatic VALUE\nossl_pkcs7_get_signer(VALUE self)\n{\n    PKCS7 *pkcs7;\n    STACK_OF(PKCS7_SIGNER_INFO) *sk;\n    int num, i;\n    VALUE ary;\n\n    GetPKCS7(self, pkcs7);\n    if (!(sk = PKCS7_get_signer_info(pkcs7)))\n        return rb_ary_new();\n    num = sk_PKCS7_SIGNER_INFO_num(sk);\n    ary = rb_ary_new_capa(num);\n    for (i=0; i<num; i++) {\n        PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(sk, i);\n        rb_ary_push(ary, ossl_pkcs7si_new(si));\n    }\n\n    return ary;\n}\n\nstatic VALUE\nossl_pkcs7_add_recipient(VALUE self, VALUE recip)\n{\n    PKCS7 *pkcs7;\n    PKCS7_RECIP_INFO *ri, *ri_new;\n\n    GetPKCS7(self, pkcs7);\n    GetPKCS7ri(recip, ri);\n\n    ri_new = ossl_PKCS7_RECIP_INFO_dup(ri);\n    if (!ri_new)\n        ossl_raise(ePKCS7Error, \"PKCS7_RECIP_INFO_dup\");\n\n    if (PKCS7_add_recipient_info(pkcs7, ri_new) != 1) {\n        PKCS7_RECIP_INFO_free(ri_new);\n        ossl_raise(ePKCS7Error, \"PKCS7_add_recipient_info\");\n    }\n\n    return self;\n}\n\nstatic VALUE\nossl_pkcs7_get_recipient(VALUE self)\n{\n    PKCS7 *pkcs7;\n    STACK_OF(PKCS7_RECIP_INFO) *sk;\n    int num, i;\n    VALUE ary;\n\n    GetPKCS7(self, pkcs7);\n    if (PKCS7_type_is_enveloped(pkcs7))\n        sk = pkcs7->d.enveloped->recipientinfo;\n    else if (PKCS7_type_is_signedAndEnveloped(pkcs7))\n        sk = pkcs7->d.signed_and_enveloped->recipientinfo;\n    else sk = NULL;\n    if (!sk) return rb_ary_new();\n    num = sk_PKCS7_RECIP_INFO_num(sk);\n    ary = rb_ary_new_capa(num);\n    for (i=0; i<num; i++) {\n        PKCS7_RECIP_INFO *ri = sk_PKCS7_RECIP_INFO_value(sk, i);\n        rb_ary_push(ary, ossl_pkcs7ri_new(ri));\n    }\n\n    return ary;\n}\n\nstatic VALUE\nossl_pkcs7_add_certificate(VALUE self, VALUE cert)\n{\n    PKCS7 *pkcs7;\n    X509 *x509;\n\n    GetPKCS7(self, pkcs7);\n    x509 = GetX509CertPtr(cert);  /* NO NEED TO DUP */\n    if (!PKCS7_add_certificate(pkcs7, x509)){\n        ossl_raise(ePKCS7Error, NULL);\n    }\n\n    return self;\n}\n\nstatic STACK_OF(X509) *\npkcs7_get_certs(VALUE self)\n{\n    PKCS7 *pkcs7;\n    STACK_OF(X509) *certs;\n    int i;\n\n    GetPKCS7(self, pkcs7);\n    i = OBJ_obj2nid(pkcs7->type);\n    switch(i){\n      case NID_pkcs7_signed:\n        certs = pkcs7->d.sign->cert;\n        break;\n      case NID_pkcs7_signedAndEnveloped:\n        certs = pkcs7->d.signed_and_enveloped->cert;\n        break;\n      default:\n        certs = NULL;\n    }\n\n    return certs;\n}\n\nstatic STACK_OF(X509_CRL) *\npkcs7_get_crls(VALUE self)\n{\n    PKCS7 *pkcs7;\n    STACK_OF(X509_CRL) *crls;\n    int i;\n\n    GetPKCS7(self, pkcs7);\n    i = OBJ_obj2nid(pkcs7->type);\n    switch(i){\n      case NID_pkcs7_signed:\n        crls = pkcs7->d.sign->crl;\n        break;\n      case NID_pkcs7_signedAndEnveloped:\n        crls = pkcs7->d.signed_and_enveloped->crl;\n        break;\n      default:\n        crls = NULL;\n    }\n\n    return crls;\n}\n\nstatic VALUE\nossl_pkcs7_set_certs_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))\n{\n    return ossl_pkcs7_add_certificate(arg, i);\n}\n\nstatic VALUE\nossl_pkcs7_set_certificates(VALUE self, VALUE ary)\n{\n    STACK_OF(X509) *certs;\n    X509 *cert;\n\n    certs = pkcs7_get_certs(self);\n    if (certs) {\n        while ((cert = sk_X509_pop(certs)))\n            X509_free(cert);\n    }\n    rb_block_call(ary, rb_intern(\"each\"), 0, 0, ossl_pkcs7_set_certs_i, self);\n\n    return ary;\n}\n\nstatic VALUE\nossl_pkcs7_get_certificates(VALUE self)\n{\n    STACK_OF(X509) *certs = pkcs7_get_certs(self);\n    if (!certs)\n        return Qnil;\n    return ossl_x509_sk2ary(certs);\n}\n\nstatic VALUE\nossl_pkcs7_add_crl(VALUE self, VALUE crl)\n{\n    PKCS7 *pkcs7;\n    X509_CRL *x509crl;\n\n    GetPKCS7(self, pkcs7); /* NO DUP needed! */\n    x509crl = GetX509CRLPtr(crl);\n    if (!PKCS7_add_crl(pkcs7, x509crl)) {\n        ossl_raise(ePKCS7Error, NULL);\n    }\n\n    return self;\n}\n\nstatic VALUE\nossl_pkcs7_set_crls_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))\n{\n    return ossl_pkcs7_add_crl(arg, i);\n}\n\nstatic VALUE\nossl_pkcs7_set_crls(VALUE self, VALUE ary)\n{\n    STACK_OF(X509_CRL) *crls;\n    X509_CRL *crl;\n\n    crls = pkcs7_get_crls(self);\n    if (crls) {\n        while ((crl = sk_X509_CRL_pop(crls)))\n            X509_CRL_free(crl);\n    }\n    rb_block_call(ary, rb_intern(\"each\"), 0, 0, ossl_pkcs7_set_crls_i, self);\n\n    return ary;\n}\n\nstatic VALUE\nossl_pkcs7_get_crls(VALUE self)\n{\n    STACK_OF(X509_CRL) *crls = pkcs7_get_crls(self);\n    if (!crls)\n        return Qnil;\n    return ossl_x509crl_sk2ary(crls);\n}\n\nstatic VALUE\nossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)\n{\n    VALUE certs, store, indata, flags;\n    STACK_OF(X509) *x509s;\n    X509_STORE *x509st;\n    int flg, ok, status = 0;\n    BIO *in, *out;\n    PKCS7 *p7;\n    VALUE data;\n\n    GetPKCS7(self, p7);\n    rb_scan_args(argc, argv, \"22\", &certs, &store, &indata, &flags);\n    x509st = GetX509StorePtr(store);\n    flg = NIL_P(flags) ? 0 : NUM2INT(flags);\n    if(NIL_P(indata)) indata = ossl_pkcs7_get_data(self);\n    in = NIL_P(indata) ? NULL : ossl_obj2bio(&indata);\n    if(NIL_P(certs)) x509s = NULL;\n    else{\n        x509s = ossl_protect_x509_ary2sk(certs, &status);\n        if(status){\n            BIO_free(in);\n            rb_jump_tag(status);\n        }\n    }\n    if(!(out = BIO_new(BIO_s_mem()))){\n        BIO_free(in);\n        sk_X509_pop_free(x509s, X509_free);\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);\n    BIO_free(in);\n    sk_X509_pop_free(x509s, X509_free);\n    data = ossl_membio2str(out);\n    ossl_pkcs7_set_data(self, data);\n    if (ok != 1) {\n        const char *msg = ERR_reason_error_string(ERR_peek_error());\n        ossl_pkcs7_set_err_string(self, msg ? rb_str_new_cstr(msg) : Qnil);\n        ossl_clear_error();\n        return Qfalse;\n    }\n    ossl_pkcs7_set_err_string(self, Qnil);\n    return Qtrue;\n}\n\nstatic VALUE\nossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self)\n{\n    VALUE pkey, cert, flags;\n    EVP_PKEY *key;\n    X509 *x509;\n    int flg;\n    PKCS7 *p7;\n    BIO *out;\n    VALUE str;\n\n    rb_scan_args(argc, argv, \"12\", &pkey, &cert, &flags);\n    key = GetPrivPKeyPtr(pkey); /* NO NEED TO DUP */\n    x509 = NIL_P(cert) ? NULL : GetX509CertPtr(cert); /* NO NEED TO DUP */\n    flg = NIL_P(flags) ? 0 : NUM2INT(flags);\n    GetPKCS7(self, p7);\n    if(!(out = BIO_new(BIO_s_mem())))\n        ossl_raise(ePKCS7Error, NULL);\n    if(!PKCS7_decrypt(p7, key, x509, out, flg)){\n        BIO_free(out);\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    str = ossl_membio2str(out); /* out will be free */\n\n    return str;\n}\n\nstatic VALUE\nossl_pkcs7_add_data(VALUE self, VALUE data)\n{\n    PKCS7 *pkcs7;\n    BIO *out, *in;\n    char buf[4096];\n    int len, ret;\n\n    GetPKCS7(self, pkcs7);\n    if (PKCS7_type_is_signed(pkcs7)) {\n        if (!PKCS7_content_new(pkcs7, NID_pkcs7_data))\n            ossl_raise(ePKCS7Error, \"PKCS7_content_new\");\n    }\n    in = ossl_obj2bio(&data);\n    if (!(out = PKCS7_dataInit(pkcs7, NULL))) {\n        BIO_free(in);\n        ossl_raise(ePKCS7Error, \"PKCS7_dataInit\");\n    }\n    for (;;) {\n        if ((len = BIO_read(in, buf, sizeof(buf))) <= 0)\n            break;\n        if (BIO_write(out, buf, len) != len) {\n            BIO_free_all(out);\n            BIO_free(in);\n            ossl_raise(ePKCS7Error, \"BIO_write\");\n        }\n    }\n    if (BIO_flush(out) <= 0) {\n        BIO_free_all(out);\n        BIO_free(in);\n        ossl_raise(ePKCS7Error, \"BIO_flush\");\n    }\n    ret = PKCS7_dataFinal(pkcs7, out);\n    BIO_free_all(out);\n    BIO_free(in);\n    if (!ret)\n        ossl_raise(ePKCS7Error, \"PKCS7_dataFinal\");\n    ossl_pkcs7_set_data(self, Qnil);\n\n    return data;\n}\n\nstatic VALUE\nossl_pkcs7_to_der(VALUE self)\n{\n    PKCS7 *pkcs7;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetPKCS7(self, pkcs7);\n    if((len = i2d_PKCS7(pkcs7, NULL)) <= 0)\n        ossl_raise(ePKCS7Error, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d_PKCS7(pkcs7, &p) <= 0)\n        ossl_raise(ePKCS7Error, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\nstatic VALUE\nossl_pkcs7_to_text(VALUE self)\n{\n    PKCS7 *pkcs7;\n    BIO *out;\n    VALUE str;\n\n    GetPKCS7(self, pkcs7);\n    if(!(out = BIO_new(BIO_s_mem())))\n        ossl_raise(ePKCS7Error, NULL);\n    if(!PKCS7_print_ctx(out, pkcs7, 0, NULL)) {\n        BIO_free(out);\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    str = ossl_membio2str(out);\n\n    return str;\n}\n\nstatic VALUE\nossl_pkcs7_to_pem(VALUE self)\n{\n    PKCS7 *pkcs7;\n    BIO *out;\n    VALUE str;\n\n    GetPKCS7(self, pkcs7);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    if (!PEM_write_bio_PKCS7(out, pkcs7)) {\n        BIO_free(out);\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    str = ossl_membio2str(out);\n\n    return str;\n}\n\n/*\n * SIGNER INFO\n */\nstatic VALUE\nossl_pkcs7si_alloc(VALUE klass)\n{\n    PKCS7_SIGNER_INFO *p7si;\n    VALUE obj;\n\n    obj = NewPKCS7si(klass);\n    if (!(p7si = PKCS7_SIGNER_INFO_new())) {\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    SetPKCS7si(obj, p7si);\n\n    return obj;\n}\n\nstatic VALUE\nossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest)\n{\n    PKCS7_SIGNER_INFO *p7si;\n    EVP_PKEY *pkey;\n    X509 *x509;\n    const EVP_MD *md;\n    VALUE md_holder;\n\n    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */\n    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */\n    md = ossl_evp_md_fetch(digest, &md_holder);\n    GetPKCS7si(self, p7si);\n    if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, md)))\n        ossl_raise(ePKCS7Error, \"PKCS7_SIGNER_INFO_set\");\n    rb_ivar_set(self, id_md_holder, md_holder);\n\n    return self;\n}\n\nstatic VALUE\nossl_pkcs7si_get_issuer(VALUE self)\n{\n    PKCS7_SIGNER_INFO *p7si;\n\n    GetPKCS7si(self, p7si);\n\n    return ossl_x509name_new(p7si->issuer_and_serial->issuer);\n}\n\nstatic VALUE\nossl_pkcs7si_get_serial(VALUE self)\n{\n    PKCS7_SIGNER_INFO *p7si;\n\n    GetPKCS7si(self, p7si);\n\n    return asn1integer_to_num(p7si->issuer_and_serial->serial);\n}\n\nstatic VALUE\nossl_pkcs7si_get_signed_time(VALUE self)\n{\n    PKCS7_SIGNER_INFO *p7si;\n    const ASN1_TYPE *asn1obj;\n\n    GetPKCS7si(self, p7si);\n\n    if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    if (asn1obj->type == V_ASN1_UTCTIME) {\n        return asn1time_to_time(asn1obj->value.utctime);\n    }\n    /*\n     * OR\n     * ossl_raise(ePKCS7Error, \"...\");\n     * ?\n     */\n\n    return Qnil;\n}\n\n/*\n * RECIPIENT INFO\n */\nstatic VALUE\nossl_pkcs7ri_alloc(VALUE klass)\n{\n    PKCS7_RECIP_INFO *p7ri;\n    VALUE obj;\n\n    obj = NewPKCS7ri(klass);\n    if (!(p7ri = PKCS7_RECIP_INFO_new())) {\n        ossl_raise(ePKCS7Error, NULL);\n    }\n    SetPKCS7ri(obj, p7ri);\n\n    return obj;\n}\n\nstatic VALUE\nossl_pkcs7ri_initialize(VALUE self, VALUE cert)\n{\n    PKCS7_RECIP_INFO *p7ri;\n    X509 *x509;\n\n    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */\n    GetPKCS7ri(self, p7ri);\n    if (PKCS7_RECIP_INFO_set(p7ri, x509) <= 0) {\n        ossl_raise(ePKCS7Error, NULL);\n    }\n\n    return self;\n}\n\nstatic VALUE\nossl_pkcs7ri_get_issuer(VALUE self)\n{\n    PKCS7_RECIP_INFO *p7ri;\n\n    GetPKCS7ri(self, p7ri);\n\n    return ossl_x509name_new(p7ri->issuer_and_serial->issuer);\n}\n\nstatic VALUE\nossl_pkcs7ri_get_serial(VALUE self)\n{\n    PKCS7_RECIP_INFO *p7ri;\n\n    GetPKCS7ri(self, p7ri);\n\n    return asn1integer_to_num(p7ri->issuer_and_serial->serial);\n}\n\nstatic VALUE\nossl_pkcs7ri_get_enc_key(VALUE self)\n{\n    PKCS7_RECIP_INFO *p7ri;\n\n    GetPKCS7ri(self, p7ri);\n\n    return asn1str_to_str(p7ri->enc_key);\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_pkcs7(void)\n{\n#undef rb_intern\n    cPKCS7 = rb_define_class_under(mOSSL, \"PKCS7\", rb_cObject);\n    ePKCS7Error = rb_define_class_under(cPKCS7, \"PKCS7Error\", eOSSLError);\n    rb_define_singleton_method(cPKCS7, \"read_smime\", ossl_pkcs7_s_read_smime, 1);\n    rb_define_singleton_method(cPKCS7, \"write_smime\", ossl_pkcs7_s_write_smime, -1);\n    rb_define_singleton_method(cPKCS7, \"sign\",  ossl_pkcs7_s_sign, -1);\n    rb_define_singleton_method(cPKCS7, \"encrypt\", ossl_pkcs7_s_encrypt, -1);\n    rb_attr(cPKCS7, rb_intern(\"data\"), 1, 0, Qfalse);\n    rb_attr(cPKCS7, rb_intern(\"error_string\"), 1, 1, Qfalse);\n    rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc);\n    rb_define_method(cPKCS7, \"initialize_copy\", ossl_pkcs7_copy, 1);\n    rb_define_method(cPKCS7, \"initialize\", ossl_pkcs7_initialize, -1);\n    rb_define_method(cPKCS7, \"type=\", ossl_pkcs7_set_type, 1);\n    rb_define_method(cPKCS7, \"type\", ossl_pkcs7_get_type, 0);\n    rb_define_method(cPKCS7, \"detached=\", ossl_pkcs7_set_detached, 1);\n    rb_define_method(cPKCS7, \"detached\", ossl_pkcs7_get_detached, 0);\n    rb_define_method(cPKCS7, \"detached?\", ossl_pkcs7_detached_p, 0);\n    rb_define_method(cPKCS7, \"cipher=\", ossl_pkcs7_set_cipher, 1);\n    rb_define_method(cPKCS7, \"add_signer\", ossl_pkcs7_add_signer, 1);\n    rb_define_method(cPKCS7, \"signers\", ossl_pkcs7_get_signer, 0);\n    rb_define_method(cPKCS7, \"add_recipient\", ossl_pkcs7_add_recipient, 1);\n    rb_define_method(cPKCS7, \"recipients\", ossl_pkcs7_get_recipient, 0);\n    rb_define_method(cPKCS7, \"add_certificate\", ossl_pkcs7_add_certificate, 1);\n    rb_define_method(cPKCS7, \"certificates=\", ossl_pkcs7_set_certificates, 1);\n    rb_define_method(cPKCS7, \"certificates\", ossl_pkcs7_get_certificates, 0);\n    rb_define_method(cPKCS7, \"add_crl\", ossl_pkcs7_add_crl, 1);\n    rb_define_method(cPKCS7, \"crls=\", ossl_pkcs7_set_crls, 1);\n    rb_define_method(cPKCS7, \"crls\", ossl_pkcs7_get_crls, 0);\n    rb_define_method(cPKCS7, \"add_data\", ossl_pkcs7_add_data, 1);\n    rb_define_alias(cPKCS7,  \"data=\", \"add_data\");\n    rb_define_method(cPKCS7, \"verify\", ossl_pkcs7_verify, -1);\n    rb_define_method(cPKCS7, \"decrypt\", ossl_pkcs7_decrypt, -1);\n    rb_define_method(cPKCS7, \"to_pem\", ossl_pkcs7_to_pem, 0);\n    rb_define_alias(cPKCS7,  \"to_s\", \"to_pem\");\n    rb_define_method(cPKCS7, \"to_der\", ossl_pkcs7_to_der, 0);\n    rb_define_method(cPKCS7, \"to_text\", ossl_pkcs7_to_text, 0);\n\n    cPKCS7Signer = rb_define_class_under(cPKCS7, \"SignerInfo\", rb_cObject);\n    rb_define_const(cPKCS7, \"Signer\", cPKCS7Signer);\n    rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc);\n    rb_define_method(cPKCS7Signer, \"initialize\", ossl_pkcs7si_initialize,3);\n    rb_define_method(cPKCS7Signer, \"issuer\", ossl_pkcs7si_get_issuer, 0);\n    rb_define_method(cPKCS7Signer, \"serial\", ossl_pkcs7si_get_serial,0);\n    rb_define_method(cPKCS7Signer,\"signed_time\",ossl_pkcs7si_get_signed_time,0);\n\n    cPKCS7Recipient = rb_define_class_under(cPKCS7,\"RecipientInfo\",rb_cObject);\n    rb_define_alloc_func(cPKCS7Recipient, ossl_pkcs7ri_alloc);\n    rb_define_method(cPKCS7Recipient, \"initialize\", ossl_pkcs7ri_initialize,1);\n    rb_define_method(cPKCS7Recipient, \"issuer\", ossl_pkcs7ri_get_issuer,0);\n    rb_define_method(cPKCS7Recipient, \"serial\", ossl_pkcs7ri_get_serial,0);\n    rb_define_method(cPKCS7Recipient, \"enc_key\", ossl_pkcs7ri_get_enc_key,0);\n\n#define DefPKCS7Const(x) rb_define_const(cPKCS7, #x, INT2NUM(PKCS7_##x))\n\n    DefPKCS7Const(TEXT);\n    DefPKCS7Const(NOCERTS);\n    DefPKCS7Const(NOSIGS);\n    DefPKCS7Const(NOCHAIN);\n    DefPKCS7Const(NOINTERN);\n    DefPKCS7Const(NOVERIFY);\n    DefPKCS7Const(DETACHED);\n    DefPKCS7Const(BINARY);\n    DefPKCS7Const(NOATTR);\n    DefPKCS7Const(NOSMIMECAP);\n\n    id_md_holder = rb_intern_const(\"EVP_MD_holder\");\n    id_cipher_holder = rb_intern_const(\"EVP_CIPHER_holder\");\n}\n"
  },
  {
    "path": "ext/openssl/ossl_pkcs7.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_PKCS7_H_)\n#define _OSSL_PKCS7_H_\n\nVALUE ossl_pkcs7_new(PKCS7 *p7);\nvoid Init_ossl_pkcs7(void);\n\n#endif /* _OSSL_PKCS7_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_pkey.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#ifdef OSSL_USE_ENGINE\n# include <openssl/engine.h>\n#endif\n\n/*\n * Classes\n */\nVALUE mPKey;\nVALUE cPKey;\nVALUE ePKeyError;\nstatic ID id_private_q;\n\nstatic void\nossl_evp_pkey_free(void *ptr)\n{\n    EVP_PKEY_free(ptr);\n}\n\n/*\n * Public\n */\nconst rb_data_type_t ossl_evp_pkey_type = {\n    \"OpenSSL/EVP_PKEY\",\n    {\n        0, ossl_evp_pkey_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\npkey_wrap0(VALUE arg)\n{\n    EVP_PKEY *pkey = (EVP_PKEY *)arg;\n    VALUE klass, obj;\n\n    switch (EVP_PKEY_base_id(pkey)) {\n#if !defined(OPENSSL_NO_RSA)\n      case EVP_PKEY_RSA: klass = cRSA; break;\n#endif\n#if !defined(OPENSSL_NO_DSA)\n      case EVP_PKEY_DSA: klass = cDSA; break;\n#endif\n#if !defined(OPENSSL_NO_DH)\n      case EVP_PKEY_DH:  klass = cDH; break;\n#endif\n#if !defined(OPENSSL_NO_EC)\n      case EVP_PKEY_EC:  klass = cEC; break;\n#endif\n      default:           klass = cPKey; break;\n    }\n    obj = rb_obj_alloc(klass);\n    RTYPEDDATA_DATA(obj) = pkey;\n    return obj;\n}\n\nVALUE\nossl_pkey_wrap(EVP_PKEY *pkey)\n{\n    VALUE obj;\n    int status;\n\n    obj = rb_protect(pkey_wrap0, (VALUE)pkey, &status);\n    if (status) {\n        EVP_PKEY_free(pkey);\n        rb_jump_tag(status);\n    }\n\n    return obj;\n}\n\n#if OSSL_OPENSSL_PREREQ(3, 0, 0)\n# include <openssl/decoder.h>\n\nstatic EVP_PKEY *\nossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)\n{\n    void *ppass = (void *)pass;\n    OSSL_DECODER_CTX *dctx;\n    EVP_PKEY *pkey = NULL;\n    int pos = 0, pos2;\n\n    dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL,\n                                         selection, NULL, NULL);\n    if (!dctx)\n        goto out;\n    if (selection == EVP_PKEY_KEYPAIR &&\n        OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,\n                                             ppass) != 1)\n        goto out;\n    while (1) {\n        if (OSSL_DECODER_from_bio(dctx, bio) == 1)\n            goto out;\n        if (BIO_eof(bio))\n            break;\n        pos2 = BIO_tell(bio);\n        if (pos2 < 0 || pos2 <= pos)\n            break;\n        ossl_clear_error();\n        pos = pos2;\n    }\n  out:\n    OSSL_BIO_reset(bio);\n    OSSL_DECODER_CTX_free(dctx);\n    return pkey;\n}\n\nEVP_PKEY *\nossl_pkey_read_generic(BIO *bio, VALUE pass)\n{\n    EVP_PKEY *pkey = NULL;\n    /* First check DER, then check PEM. */\n    const char *input_types[] = {\"DER\", \"PEM\"};\n    int input_type_num = (int)(sizeof(input_types) / sizeof(char *));\n    /*\n     * Non-zero selections to try to decode.\n     *\n     * See EVP_PKEY_fromdata(3) - Selections to see all the selections.\n     *\n     * This is a workaround for the decoder failing to decode or returning\n     * bogus keys with selection 0, if a key management provider is different\n     * from a decoder provider. The workaround is to avoid using selection 0.\n     *\n     * Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10\n     * Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z\n     *\n     * See https://github.com/openssl/openssl/pull/21519 for details.\n     *\n     * First check for private key formats (EVP_PKEY_KEYPAIR). This is to keep\n     * compatibility with ruby/openssl < 3.0 which decoded the following as a\n     * private key.\n     *\n     *     $ openssl ecparam -name prime256v1 -genkey -outform PEM\n     *     -----BEGIN EC PARAMETERS-----\n     *     BggqhkjOPQMBBw==\n     *     -----END EC PARAMETERS-----\n     *     -----BEGIN EC PRIVATE KEY-----\n     *     MHcCAQEEIAG8ugBbA5MHkqnZ9ujQF93OyUfL9tk8sxqM5Wv5tKg5oAoGCCqGSM49\n     *     AwEHoUQDQgAEVcjhJfkwqh5C7kGuhAf8XaAjVuG5ADwb5ayg/cJijCgs+GcXeedj\n     *     86avKpGH84DXUlB23C/kPt+6fXYlitUmXQ==\n     *     -----END EC PRIVATE KEY-----\n     *\n     * While the first PEM block is a proper encoding of ECParameters, thus\n     * OSSL_DECODER_from_bio() would pick it up, ruby/openssl used to return\n     * the latter instead. Existing applications expect this behavior.\n     *\n     * Note that normally, the input is supposed to contain a single decodable\n     * PEM block only, so this special handling should not create a new problem.\n     *\n     * Note that we need to create the OSSL_DECODER_CTX variable each time when\n     * we use the different selection as a workaround.\n     * See https://github.com/openssl/openssl/issues/20657 for details.\n     */\n    int selections[] = {\n        EVP_PKEY_KEYPAIR,\n        EVP_PKEY_KEY_PARAMETERS,\n        EVP_PKEY_PUBLIC_KEY\n    };\n    int selection_num = (int)(sizeof(selections) / sizeof(int));\n    int i, j;\n\n    for (i = 0; i < input_type_num; i++) {\n        for (j = 0; j < selection_num; j++) {\n            pkey = ossl_pkey_read(bio, input_types[i], selections[j], pass);\n            if (pkey) {\n                goto out;\n            }\n        }\n    }\n  out:\n    return pkey;\n}\n#else\nEVP_PKEY *\nossl_pkey_read_generic(BIO *bio, VALUE pass)\n{\n    void *ppass = (void *)pass;\n    EVP_PKEY *pkey;\n\n    if ((pkey = d2i_PrivateKey_bio(bio, NULL)))\n        goto out;\n    OSSL_BIO_reset(bio);\n    if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))\n        goto out;\n    OSSL_BIO_reset(bio);\n    if ((pkey = d2i_PUBKEY_bio(bio, NULL)))\n        goto out;\n    OSSL_BIO_reset(bio);\n    /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */\n    if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))\n        goto out;\n    OSSL_BIO_reset(bio);\n    if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))\n        goto out;\n    OSSL_BIO_reset(bio);\n    if ((pkey = PEM_read_bio_Parameters(bio, NULL)))\n        goto out;\n\n  out:\n    return pkey;\n}\n#endif\n\n/*\n *  call-seq:\n *     OpenSSL::PKey.read(string [, pwd ]) -> PKey\n *     OpenSSL::PKey.read(io [, pwd ]) -> PKey\n *\n * Reads a DER or PEM encoded string from _string_ or _io_ and returns an\n * instance of the appropriate PKey class.\n *\n * === Parameters\n * * _string_ is a DER- or PEM-encoded string containing an arbitrary private\n *   or public key.\n * * _io_ is an instance of IO containing a DER- or PEM-encoded\n *   arbitrary private or public key.\n * * _pwd_ is an optional password in case _string_ or _io_ is an encrypted\n *   PEM resource.\n */\nstatic VALUE\nossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    BIO *bio;\n    VALUE data, pass;\n\n    rb_scan_args(argc, argv, \"11\", &data, &pass);\n    bio = ossl_obj2bio(&data);\n    pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));\n    BIO_free(bio);\n    if (!pkey)\n        ossl_raise(ePKeyError, \"Could not parse PKey\");\n    return ossl_pkey_wrap(pkey);\n}\n\nstatic VALUE\npkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))\n{\n    VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1);\n    EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v;\n\n    if (SYMBOL_P(key))\n        key = rb_sym2str(key);\n    value = rb_String(value);\n\n    if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_ctrl_str(ctx, %+\"PRIsVALUE\", %+\"PRIsVALUE\")\",\n                   key, value);\n    return Qnil;\n}\n\nstatic VALUE\npkey_ctx_apply_options0(VALUE args_v)\n{\n    VALUE *args = (VALUE *)args_v;\n    Check_Type(args[1], T_HASH);\n\n    rb_block_call(args[1], rb_intern(\"each\"), 0, NULL,\n                  pkey_ctx_apply_options_i, args[0]);\n    return Qnil;\n}\n\nstatic void\npkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state)\n{\n    VALUE args[2];\n    args[0] = (VALUE)ctx;\n    args[1] = options;\n\n    rb_protect(pkey_ctx_apply_options0, (VALUE)args, state);\n}\n\nstruct pkey_blocking_generate_arg {\n    EVP_PKEY_CTX *ctx;\n    EVP_PKEY *pkey;\n    int state;\n    unsigned int yield: 1;\n    unsigned int genparam: 1;\n    unsigned int interrupted: 1;\n};\n\nstatic VALUE\npkey_gen_cb_yield(VALUE ctx_v)\n{\n    EVP_PKEY_CTX *ctx = (void *)ctx_v;\n    int i, info_num;\n    VALUE *argv;\n\n    info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1);\n    argv = ALLOCA_N(VALUE, info_num);\n    for (i = 0; i < info_num; i++)\n        argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i));\n\n    return rb_yield_values2(info_num, argv);\n}\n\nstatic VALUE\ncall_check_ints0(VALUE arg)\n{\n    rb_thread_check_ints();\n    return Qnil;\n}\n\nstatic void *\ncall_check_ints(void *arg)\n{\n    int state;\n    rb_protect(call_check_ints0, Qnil, &state);\n    return (void *)(VALUE)state;\n}\n\nstatic int\npkey_gen_cb(EVP_PKEY_CTX *ctx)\n{\n    struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx);\n    int state;\n\n    if (arg->yield) {\n        rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state);\n        if (state) {\n            arg->state = state;\n            return 0;\n        }\n    }\n    if (arg->interrupted) {\n        arg->interrupted = 0;\n        state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);\n        if (state) {\n            arg->state = state;\n            return 0;\n        }\n    }\n    return 1;\n}\n\nstatic void\npkey_blocking_gen_stop(void *ptr)\n{\n    struct pkey_blocking_generate_arg *arg = ptr;\n    arg->interrupted = 1;\n}\n\nstatic void *\npkey_blocking_gen(void *ptr)\n{\n    struct pkey_blocking_generate_arg *arg = ptr;\n\n    if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0)\n        return NULL;\n    if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0)\n        return NULL;\n    return arg->pkey;\n}\n\nstatic VALUE\npkey_generate(int argc, VALUE *argv, VALUE self, int genparam)\n{\n    EVP_PKEY_CTX *ctx;\n    VALUE alg, options;\n    struct pkey_blocking_generate_arg gen_arg = { 0 };\n    int state;\n\n    rb_scan_args(argc, argv, \"11\", &alg, &options);\n    if (rb_obj_is_kind_of(alg, cPKey)) {\n        EVP_PKEY *base_pkey;\n\n        GetPKey(alg, base_pkey);\n        ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */);\n        if (!ctx)\n            ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n    }\n    else {\n#if OSSL_OPENSSL_PREREQ(3, 0, 0)\n        ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL);\n        if (!ctx)\n            ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new_from_name\");\n#else\n        const EVP_PKEY_ASN1_METHOD *ameth;\n        ENGINE *tmpeng;\n        int pkey_id;\n\n        StringValue(alg);\n        ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg),\n                                       RSTRING_LENINT(alg));\n        if (!ameth)\n            ossl_raise(ePKeyError, \"algorithm %\"PRIsVALUE\" not found\", alg);\n        EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);\n#if !defined(OPENSSL_NO_ENGINE)\n        if (tmpeng)\n            ENGINE_finish(tmpeng);\n#endif\n\n        ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */);\n        if (!ctx)\n            ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new_id\");\n#endif\n    }\n\n    if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_paramgen_init\");\n    }\n    if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_keygen_init\");\n    }\n\n    if (!NIL_P(options)) {\n        pkey_ctx_apply_options(ctx, options, &state);\n        if (state) {\n            EVP_PKEY_CTX_free(ctx);\n            rb_jump_tag(state);\n        }\n    }\n\n    gen_arg.genparam = genparam;\n    gen_arg.ctx = ctx;\n    gen_arg.yield = rb_block_given_p();\n    EVP_PKEY_CTX_set_app_data(ctx, &gen_arg);\n    EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb);\n    if (gen_arg.yield)\n        pkey_blocking_gen(&gen_arg);\n    else\n        rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg,\n                                   pkey_blocking_gen_stop, &gen_arg);\n    EVP_PKEY_CTX_free(ctx);\n    if (!gen_arg.pkey) {\n        if (gen_arg.state) {\n            ossl_clear_error();\n            rb_jump_tag(gen_arg.state);\n        }\n        else {\n            ossl_raise(ePKeyError, genparam ? \"EVP_PKEY_paramgen\" : \"EVP_PKEY_keygen\");\n        }\n    }\n\n    return ossl_pkey_wrap(gen_arg.pkey);\n}\n\n/*\n * call-seq:\n *    OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey\n *\n * Generates new parameters for the algorithm. _algo_name_ is a String that\n * represents the algorithm. The optional argument _options_ is a Hash that\n * specifies the options specific to the algorithm. The order of the options\n * can be important.\n *\n * A block can be passed optionally. The meaning of the arguments passed to\n * the block varies depending on the implementation of the algorithm. The block\n * may be called once or multiple times, or may not even be called.\n *\n * For the supported options, see the documentation for the 'openssl genpkey'\n * utility command.\n *\n * == Example\n *   pkey = OpenSSL::PKey.generate_parameters(\"DSA\", \"dsa_paramgen_bits\" => 2048)\n *   p pkey.p.num_bits #=> 2048\n */\nstatic VALUE\nossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self)\n{\n    return pkey_generate(argc, argv, self, 1);\n}\n\n/*\n * call-seq:\n *    OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey\n *    OpenSSL::PKey.generate_key(pkey [, options]) -> pkey\n *\n * Generates a new key (pair).\n *\n * If a String is given as the first argument, it generates a new random key\n * for the algorithm specified by the name just as ::generate_parameters does.\n * If an OpenSSL::PKey::PKey is given instead, it generates a new random key\n * for the same algorithm as the key, using the parameters the key contains.\n *\n * See ::generate_parameters for the details of _options_ and the given block.\n *\n * == Example\n *   pkey_params = OpenSSL::PKey.generate_parameters(\"DSA\", \"dsa_paramgen_bits\" => 2048)\n *   pkey_params.priv_key #=> nil\n *   pkey = OpenSSL::PKey.generate_key(pkey_params)\n *   pkey.priv_key #=> #<OpenSSL::BN 6277...\n */\nstatic VALUE\nossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)\n{\n    return pkey_generate(argc, argv, self, 0);\n}\n\n/*\n * TODO: There is no convenient way to check the presence of public key\n * components on OpenSSL 3.0. But since keys are immutable on 3.0, pkeys without\n * these should only be created by OpenSSL::PKey.generate_parameters or by\n * parsing DER-/PEM-encoded string. We would need another flag for that.\n */\nvoid\nossl_pkey_check_public_key(const EVP_PKEY *pkey)\n{\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n    if (EVP_PKEY_missing_parameters(pkey))\n        ossl_raise(ePKeyError, \"parameters missing\");\n#else\n    void *ptr;\n    const BIGNUM *n, *e, *pubkey;\n\n    if (EVP_PKEY_missing_parameters(pkey))\n        ossl_raise(ePKeyError, \"parameters missing\");\n\n    ptr = EVP_PKEY_get0(pkey);\n    switch (EVP_PKEY_base_id(pkey)) {\n      case EVP_PKEY_RSA:\n        RSA_get0_key(ptr, &n, &e, NULL);\n        if (n && e)\n            return;\n        break;\n      case EVP_PKEY_DSA:\n        DSA_get0_key(ptr, &pubkey, NULL);\n        if (pubkey)\n            return;\n        break;\n      case EVP_PKEY_DH:\n        DH_get0_key(ptr, &pubkey, NULL);\n        if (pubkey)\n            return;\n        break;\n#if !defined(OPENSSL_NO_EC)\n      case EVP_PKEY_EC:\n        if (EC_KEY_get0_public_key(ptr))\n            return;\n        break;\n#endif\n      default:\n        /* unsupported type; assuming ok */\n        return;\n    }\n    ossl_raise(ePKeyError, \"public key missing\");\n#endif\n}\n\nEVP_PKEY *\nGetPKeyPtr(VALUE obj)\n{\n    EVP_PKEY *pkey;\n\n    GetPKey(obj, pkey);\n\n    return pkey;\n}\n\nEVP_PKEY *\nGetPrivPKeyPtr(VALUE obj)\n{\n    EVP_PKEY *pkey;\n\n    GetPKey(obj, pkey);\n    if (OSSL_PKEY_IS_PRIVATE(obj))\n        return pkey;\n    /*\n     * The EVP API does not provide a way to check if the EVP_PKEY has private\n     * components. Assuming it does...\n     */\n    if (!rb_respond_to(obj, id_private_q))\n        return pkey;\n    if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL)))\n        return pkey;\n\n    rb_raise(rb_eArgError, \"private key is needed\");\n}\n\nEVP_PKEY *\nDupPKeyPtr(VALUE obj)\n{\n    EVP_PKEY *pkey;\n\n    GetPKey(obj, pkey);\n    EVP_PKEY_up_ref(pkey);\n\n    return pkey;\n}\n\n/*\n * Private\n */\nstatic VALUE\nossl_pkey_alloc(VALUE klass)\n{\n    return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);\n}\n\n/*\n *  call-seq:\n *      PKeyClass.new -> self\n *\n * Because PKey is an abstract class, actually calling this method explicitly\n * will raise a NotImplementedError.\n */\nstatic VALUE\nossl_pkey_initialize(VALUE self)\n{\n    if (rb_obj_is_instance_of(self, cPKey)) {\n        ossl_raise(rb_eTypeError, \"OpenSSL::PKey::PKey can't be instantiated directly\");\n    }\n    return self;\n}\n\n#ifdef HAVE_EVP_PKEY_DUP\n/* :nodoc: */\nstatic VALUE\nossl_pkey_initialize_copy(VALUE self, VALUE other)\n{\n    EVP_PKEY *pkey, *pkey_other;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n    if (pkey_other) {\n        pkey = EVP_PKEY_dup(pkey_other);\n        if (!pkey)\n            ossl_raise(ePKeyError, \"EVP_PKEY_dup\");\n        RTYPEDDATA_DATA(self) = pkey;\n    }\n    return self;\n}\n#endif\n\n#ifndef OSSL_USE_PROVIDER\nstatic int\nlookup_pkey_type(VALUE type)\n{\n    const EVP_PKEY_ASN1_METHOD *ameth;\n    int pkey_id;\n\n    StringValue(type);\n    /*\n     * XXX: EVP_PKEY_asn1_find_str() looks up a PEM type string. Should we use\n     * OBJ_txt2nid() instead (and then somehow check if the NID is an acceptable\n     * EVP_PKEY type)?\n     * It is probably fine, though, since it can handle all algorithms that\n     * support raw keys in 1.1.1: { X25519, X448, ED25519, ED448, HMAC }.\n     */\n    ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));\n    if (!ameth)\n        ossl_raise(ePKeyError, \"algorithm %\"PRIsVALUE\" not found\", type);\n    EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);\n    return pkey_id;\n}\n#endif\n\n/*\n *  call-seq:\n *      OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey\n *\n * See the OpenSSL documentation for EVP_PKEY_new_raw_private_key()\n */\n\nstatic VALUE\nossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key)\n{\n    EVP_PKEY *pkey;\n    size_t keylen;\n\n    StringValue(key);\n    keylen = RSTRING_LEN(key);\n\n#ifdef OSSL_USE_PROVIDER\n    pkey = EVP_PKEY_new_raw_private_key_ex(NULL, StringValueCStr(type), NULL,\n                                           (unsigned char *)RSTRING_PTR(key),\n                                           keylen);\n    if (!pkey)\n        ossl_raise(ePKeyError, \"EVP_PKEY_new_raw_private_key_ex\");\n#else\n    int pkey_id = lookup_pkey_type(type);\n    pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);\n    if (!pkey)\n        ossl_raise(ePKeyError, \"EVP_PKEY_new_raw_private_key\");\n#endif\n\n    return ossl_pkey_wrap(pkey);\n}\n\n/*\n *  call-seq:\n *      OpenSSL::PKey.new_raw_public_key(algo, string) -> PKey\n *\n * See the OpenSSL documentation for EVP_PKEY_new_raw_public_key()\n */\n\nstatic VALUE\nossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key)\n{\n    EVP_PKEY *pkey;\n    size_t keylen;\n\n    StringValue(key);\n    keylen = RSTRING_LEN(key);\n\n#ifdef OSSL_USE_PROVIDER\n    pkey = EVP_PKEY_new_raw_public_key_ex(NULL, StringValueCStr(type), NULL,\n                                          (unsigned char *)RSTRING_PTR(key),\n                                          keylen);\n    if (!pkey)\n        ossl_raise(ePKeyError, \"EVP_PKEY_new_raw_public_key_ex\");\n#else\n    int pkey_id = lookup_pkey_type(type);\n    pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);\n    if (!pkey)\n        ossl_raise(ePKeyError, \"EVP_PKEY_new_raw_public_key\");\n#endif\n\n    return ossl_pkey_wrap(pkey);\n}\n\n/*\n * call-seq:\n *    pkey.oid -> string\n *\n * Returns the short name of the OID associated with _pkey_.\n */\nstatic VALUE\nossl_pkey_oid(VALUE self)\n{\n    EVP_PKEY *pkey;\n    int nid;\n\n    GetPKey(self, pkey);\n    nid = EVP_PKEY_id(pkey);\n#ifdef OSSL_USE_PROVIDER\n    if (nid == EVP_PKEY_KEYMGMT)\n        ossl_raise(ePKeyError, \"EVP_PKEY_id\");\n#endif\n    return rb_str_new_cstr(OBJ_nid2sn(nid));\n}\n\n/*\n * call-seq:\n *    pkey.inspect -> string\n *\n * Returns a string describing the PKey object.\n */\nstatic VALUE\nossl_pkey_inspect(VALUE self)\n{\n    EVP_PKEY *pkey;\n\n    GetPKey(self, pkey);\n    VALUE str = rb_sprintf(\"#<%\"PRIsVALUE\":%p\",\n                           rb_obj_class(self), (void *)self);\n    int nid = EVP_PKEY_id(pkey);\n#ifdef OSSL_USE_PROVIDER\n    if (nid != EVP_PKEY_KEYMGMT)\n#endif\n    rb_str_catf(str, \" oid=%s\", OBJ_nid2sn(nid));\n#ifdef OSSL_USE_PROVIDER\n    rb_str_catf(str, \" type_name=%s\", EVP_PKEY_get0_type_name(pkey));\n    const OSSL_PROVIDER *prov = EVP_PKEY_get0_provider(pkey);\n    if (prov)\n        rb_str_catf(str, \" provider=%s\", OSSL_PROVIDER_get0_name(prov));\n#endif\n    rb_str_catf(str, \">\");\n    return str;\n}\n\n/*\n * call-seq:\n *    pkey.to_text -> string\n *\n * Dumps key parameters, public key, and private key components contained in\n * the key into a human-readable text.\n *\n * This is intended for debugging purpose.\n *\n * See also the man page EVP_PKEY_print_private(3).\n */\nstatic VALUE\nossl_pkey_to_text(VALUE self)\n{\n    EVP_PKEY *pkey;\n    BIO *bio;\n\n    GetPKey(self, pkey);\n    if (!(bio = BIO_new(BIO_s_mem())))\n        ossl_raise(ePKeyError, \"BIO_new\");\n\n    if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)\n        goto out;\n    OSSL_BIO_reset(bio);\n    if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)\n        goto out;\n    OSSL_BIO_reset(bio);\n    if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)\n        goto out;\n\n    BIO_free(bio);\n    ossl_raise(ePKeyError, \"EVP_PKEY_print_params\");\n\n  out:\n    return ossl_membio2str(bio);\n}\n\nVALUE\nossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)\n{\n    EVP_PKEY *pkey;\n    VALUE cipher, pass, cipher_holder;\n    const EVP_CIPHER *enc = NULL;\n    BIO *bio;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"02\", &cipher, &pass);\n    if (!NIL_P(cipher)) {\n        enc = ossl_evp_cipher_fetch(cipher, &cipher_holder);\n        pass = ossl_pem_passwd_value(pass);\n    }\n\n    bio = BIO_new(BIO_s_mem());\n    if (!bio)\n        ossl_raise(ePKeyError, \"BIO_new\");\n    if (to_der) {\n        if (!i2d_PrivateKey_bio(bio, pkey)) {\n            BIO_free(bio);\n            ossl_raise(ePKeyError, \"i2d_PrivateKey_bio\");\n        }\n    }\n    else {\n        if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,\n                                                  ossl_pem_passwd_cb,\n                                                  (void *)pass)) {\n            BIO_free(bio);\n            ossl_raise(ePKeyError, \"PEM_write_bio_PrivateKey_traditional\");\n        }\n    }\n    return ossl_membio2str(bio);\n}\n\nstatic VALUE\ndo_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)\n{\n    EVP_PKEY *pkey;\n    VALUE cipher, pass, cipher_holder;\n    const EVP_CIPHER *enc = NULL;\n    BIO *bio;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"02\", &cipher, &pass);\n    if (argc > 0) {\n        /*\n         * TODO: EncryptedPrivateKeyInfo actually has more options.\n         * Should they be exposed?\n         */\n        enc = ossl_evp_cipher_fetch(cipher, &cipher_holder);\n        pass = ossl_pem_passwd_value(pass);\n    }\n\n    bio = BIO_new(BIO_s_mem());\n    if (!bio)\n        ossl_raise(ePKeyError, \"BIO_new\");\n    if (to_der) {\n        if (!i2d_PKCS8PrivateKey_bio(bio, pkey, enc, NULL, 0,\n                                     ossl_pem_passwd_cb, (void *)pass)) {\n            BIO_free(bio);\n            ossl_raise(ePKeyError, \"i2d_PKCS8PrivateKey_bio\");\n        }\n    }\n    else {\n        if (!PEM_write_bio_PKCS8PrivateKey(bio, pkey, enc, NULL, 0,\n                                           ossl_pem_passwd_cb, (void *)pass)) {\n            BIO_free(bio);\n            ossl_raise(ePKeyError, \"PEM_write_bio_PKCS8PrivateKey\");\n        }\n    }\n    return ossl_membio2str(bio);\n}\n\n/*\n * call-seq:\n *    pkey.private_to_der                   -> string\n *    pkey.private_to_der(cipher, password) -> string\n *\n * Serializes the private key to DER-encoded PKCS #8 format. If called without\n * arguments, unencrypted PKCS #8 PrivateKeyInfo format is used. If called with\n * a cipher name and a password, PKCS #8 EncryptedPrivateKeyInfo format with\n * PBES2 encryption scheme is used.\n */\nstatic VALUE\nossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)\n{\n    return do_pkcs8_export(argc, argv, self, 1);\n}\n\n/*\n * call-seq:\n *    pkey.private_to_pem                   -> string\n *    pkey.private_to_pem(cipher, password) -> string\n *\n * Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der\n * for more details.\n *\n * An unencrypted PEM-encoded key will look like:\n *\n *   -----BEGIN PRIVATE KEY-----\n *   [...]\n *   -----END PRIVATE KEY-----\n *\n * An encrypted PEM-encoded key will look like:\n *\n *   -----BEGIN ENCRYPTED PRIVATE KEY-----\n *   [...]\n *   -----END ENCRYPTED PRIVATE KEY-----\n */\nstatic VALUE\nossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)\n{\n    return do_pkcs8_export(argc, argv, self, 0);\n}\n\n/*\n *  call-seq:\n *     pkey.raw_private_key   => string\n *\n *  See the OpenSSL documentation for EVP_PKEY_get_raw_private_key()\n */\n\nstatic VALUE\nossl_pkey_raw_private_key(VALUE self)\n{\n    EVP_PKEY *pkey;\n    VALUE str;\n    size_t len;\n\n    GetPKey(self, pkey);\n    if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1)\n        ossl_raise(ePKeyError, \"EVP_PKEY_get_raw_private_key\");\n    str = rb_str_new(NULL, len);\n\n    if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)\n        ossl_raise(ePKeyError, \"EVP_PKEY_get_raw_private_key\");\n\n    rb_str_set_len(str, len);\n\n    return str;\n}\n\nVALUE\nossl_pkey_export_spki(VALUE self, int to_der)\n{\n    EVP_PKEY *pkey;\n    BIO *bio;\n\n    GetPKey(self, pkey);\n    ossl_pkey_check_public_key(pkey);\n    bio = BIO_new(BIO_s_mem());\n    if (!bio)\n        ossl_raise(ePKeyError, \"BIO_new\");\n    if (to_der) {\n        if (!i2d_PUBKEY_bio(bio, pkey)) {\n            BIO_free(bio);\n            ossl_raise(ePKeyError, \"i2d_PUBKEY_bio\");\n        }\n    }\n    else {\n        if (!PEM_write_bio_PUBKEY(bio, pkey)) {\n            BIO_free(bio);\n            ossl_raise(ePKeyError, \"PEM_write_bio_PUBKEY\");\n        }\n    }\n    return ossl_membio2str(bio);\n}\n\n/*\n * call-seq:\n *    pkey.public_to_der -> string\n *\n * Serializes the public key to DER-encoded X.509 SubjectPublicKeyInfo format.\n */\nstatic VALUE\nossl_pkey_public_to_der(VALUE self)\n{\n    return ossl_pkey_export_spki(self, 1);\n}\n\n/*\n * call-seq:\n *    pkey.public_to_pem -> string\n *\n * Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.\n *\n * A PEM-encoded key will look like:\n *\n *   -----BEGIN PUBLIC KEY-----\n *   [...]\n *   -----END PUBLIC KEY-----\n */\nstatic VALUE\nossl_pkey_public_to_pem(VALUE self)\n{\n    return ossl_pkey_export_spki(self, 0);\n}\n\n/*\n *  call-seq:\n *     pkey.raw_public_key   => string\n *\n *  See the OpenSSL documentation for EVP_PKEY_get_raw_public_key()\n */\n\nstatic VALUE\nossl_pkey_raw_public_key(VALUE self)\n{\n    EVP_PKEY *pkey;\n    VALUE str;\n    size_t len;\n\n    GetPKey(self, pkey);\n    if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1)\n        ossl_raise(ePKeyError, \"EVP_PKEY_get_raw_public_key\");\n    str = rb_str_new(NULL, len);\n\n    if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)\n        ossl_raise(ePKeyError, \"EVP_PKEY_get_raw_public_key\");\n\n    rb_str_set_len(str, len);\n\n    return str;\n}\n\n/*\n *  call-seq:\n *      pkey.compare?(another_pkey) -> true | false\n *\n * Used primarily to check if an OpenSSL::X509::Certificate#public_key compares to its private key.\n *\n * == Example\n *   x509 = OpenSSL::X509::Certificate.new(pem_encoded_certificate)\n *   rsa_key = OpenSSL::PKey::RSA.new(pem_encoded_private_key)\n *\n *   rsa_key.compare?(x509.public_key) => true | false\n */\nstatic VALUE\nossl_pkey_compare(VALUE self, VALUE other)\n{\n    int ret;\n    EVP_PKEY *selfPKey;\n    EVP_PKEY *otherPKey;\n\n    GetPKey(self, selfPKey);\n    GetPKey(other, otherPKey);\n\n    /* Explicitly check the key type given EVP_PKEY_ASN1_METHOD(3)\n     * docs param_cmp could return any negative number.\n     */\n    if (EVP_PKEY_id(selfPKey) != EVP_PKEY_id(otherPKey))\n        ossl_raise(rb_eTypeError, \"cannot match different PKey types\");\n\n    ret = EVP_PKEY_eq(selfPKey, otherPKey);\n\n    if (ret == 0)\n        return Qfalse;\n    else if (ret == 1)\n        return Qtrue;\n    else\n        ossl_raise(ePKeyError, \"EVP_PKEY_eq\");\n}\n\n/*\n * call-seq:\n *    pkey.sign(digest, data [, options]) -> string\n *\n * Hashes and signs the +data+ using a message digest algorithm +digest+ and\n * a private key +pkey+.\n *\n * See #verify for the verification operation.\n *\n * See also the man page EVP_DigestSign(3).\n *\n * +digest+::\n *   A String that represents the message digest algorithm name, or +nil+\n *   if the PKey type requires no digest algorithm.\n *   For backwards compatibility, this can be an instance of OpenSSL::Digest.\n *   Its state will not affect the signature.\n * +data+::\n *   A String. The data to be hashed and signed.\n * +options+::\n *   A Hash that contains algorithm specific control operations to \\OpenSSL.\n *   See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.\n *   +options+ parameter was added in version 3.0.\n *\n * Example:\n *   data = \"Sign me!\"\n *   pkey = OpenSSL::PKey.generate_key(\"RSA\", rsa_keygen_bits: 2048)\n *   signopts = { rsa_padding_mode: \"pss\" }\n *   signature = pkey.sign(\"SHA256\", data, signopts)\n *\n *   # Creates a copy of the RSA key pkey, but without the private components\n *   pub_key = pkey.public_key\n *   puts pub_key.verify(\"SHA256\", signature, data, signopts) # => true\n */\nstatic VALUE\nossl_pkey_sign(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    VALUE digest, data, options, sig, md_holder;\n    const EVP_MD *md = NULL;\n    EVP_MD_CTX *ctx;\n    EVP_PKEY_CTX *pctx;\n    size_t siglen;\n    int state;\n\n    pkey = GetPrivPKeyPtr(self);\n    rb_scan_args(argc, argv, \"21\", &digest, &data, &options);\n    if (!NIL_P(digest))\n        md = ossl_evp_md_fetch(digest, &md_holder);\n    StringValue(data);\n\n    ctx = EVP_MD_CTX_new();\n    if (!ctx)\n        ossl_raise(ePKeyError, \"EVP_MD_CTX_new\");\n    if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {\n        EVP_MD_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_DigestSignInit\");\n    }\n    if (!NIL_P(options)) {\n        pkey_ctx_apply_options(pctx, options, &state);\n        if (state) {\n            EVP_MD_CTX_free(ctx);\n            rb_jump_tag(state);\n        }\n    }\n    if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),\n                       RSTRING_LEN(data)) < 1) {\n        EVP_MD_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_DigestSign\");\n    }\n    if (siglen > LONG_MAX) {\n        EVP_MD_CTX_free(ctx);\n        rb_raise(ePKeyError, \"signature would be too large\");\n    }\n    sig = ossl_str_new(NULL, (long)siglen, &state);\n    if (state) {\n        EVP_MD_CTX_free(ctx);\n        rb_jump_tag(state);\n    }\n    if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen,\n                       (unsigned char *)RSTRING_PTR(data),\n                       RSTRING_LEN(data)) < 1) {\n        EVP_MD_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_DigestSign\");\n    }\n    EVP_MD_CTX_free(ctx);\n    rb_str_set_len(sig, siglen);\n    return sig;\n}\n\n/*\n * call-seq:\n *    pkey.verify(digest, signature, data [, options]) -> true or false\n *\n * Verifies the +signature+ for the +data+ using a message digest algorithm\n * +digest+ and a public key +pkey+.\n *\n * Returns +true+ if the signature is successfully verified, +false+ otherwise.\n * The caller must check the return value.\n *\n * See #sign for the signing operation and an example.\n *\n * See also the man page EVP_DigestVerify(3).\n *\n * +digest+::\n *   See #sign.\n * +signature+::\n *   A String containing the signature to be verified.\n * +data+::\n *   See #sign.\n * +options+::\n *   See #sign. +options+ parameter was added in version 3.0.\n */\nstatic VALUE\nossl_pkey_verify(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    VALUE digest, sig, data, options, md_holder;\n    const EVP_MD *md = NULL;\n    EVP_MD_CTX *ctx;\n    EVP_PKEY_CTX *pctx;\n    int state, ret;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"31\", &digest, &sig, &data, &options);\n    ossl_pkey_check_public_key(pkey);\n    if (!NIL_P(digest))\n        md = ossl_evp_md_fetch(digest, &md_holder);\n    StringValue(sig);\n    StringValue(data);\n\n    ctx = EVP_MD_CTX_new();\n    if (!ctx)\n        ossl_raise(ePKeyError, \"EVP_MD_CTX_new\");\n    if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {\n        EVP_MD_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_DigestVerifyInit\");\n    }\n    if (!NIL_P(options)) {\n        pkey_ctx_apply_options(pctx, options, &state);\n        if (state) {\n            EVP_MD_CTX_free(ctx);\n            rb_jump_tag(state);\n        }\n    }\n    ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),\n                           RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),\n                           RSTRING_LEN(data));\n    EVP_MD_CTX_free(ctx);\n    if (ret < 0)\n        ossl_raise(ePKeyError, \"EVP_DigestVerify\");\n    if (ret)\n        return Qtrue;\n    else {\n        ossl_clear_error();\n        return Qfalse;\n    }\n}\n\n/*\n * call-seq:\n *    pkey.sign_raw(digest, data [, options]) -> string\n *\n * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be\n * hashed by +digest+ automatically.\n *\n * See #verify_raw for the verification operation.\n *\n * Added in version 3.0. See also the man page EVP_PKEY_sign(3).\n *\n * +digest+::\n *   A String that represents the message digest algorithm name, or +nil+\n *   if the PKey type requires no digest algorithm.\n *   Although this method will not hash +data+ with it, this parameter may still\n *   be required depending on the signature algorithm.\n * +data+::\n *   A String. The data to be signed.\n * +options+::\n *   A Hash that contains algorithm specific control operations to \\OpenSSL.\n *   See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.\n *\n * Example:\n *   data = \"Sign me!\"\n *   hash = OpenSSL::Digest.digest(\"SHA256\", data)\n *   pkey = OpenSSL::PKey.generate_key(\"RSA\", rsa_keygen_bits: 2048)\n *   signopts = { rsa_padding_mode: \"pss\" }\n *   signature = pkey.sign_raw(\"SHA256\", hash, signopts)\n *\n *   # Creates a copy of the RSA key pkey, but without the private components\n *   pub_key = pkey.public_key\n *   puts pub_key.verify_raw(\"SHA256\", signature, hash, signopts) # => true\n */\nstatic VALUE\nossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    VALUE digest, data, options, sig, md_holder;\n    const EVP_MD *md = NULL;\n    EVP_PKEY_CTX *ctx;\n    size_t outlen;\n    int state;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"21\", &digest, &data, &options);\n    if (!NIL_P(digest))\n        md = ossl_evp_md_fetch(digest, &md_holder);\n    StringValue(data);\n\n    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);\n    if (!ctx)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n    if (EVP_PKEY_sign_init(ctx) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_sign_init\");\n    }\n    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_set_signature_md\");\n    }\n    if (!NIL_P(options)) {\n        pkey_ctx_apply_options(ctx, options, &state);\n        if (state) {\n            EVP_PKEY_CTX_free(ctx);\n            rb_jump_tag(state);\n        }\n    }\n    if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data),\n                      RSTRING_LEN(data)) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_sign\");\n    }\n    if (outlen > LONG_MAX) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_raise(ePKeyError, \"signature would be too large\");\n    }\n    sig = ossl_str_new(NULL, (long)outlen, &state);\n    if (state) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_jump_tag(state);\n    }\n    if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen,\n                      (unsigned char *)RSTRING_PTR(data),\n                      RSTRING_LEN(data)) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_sign\");\n    }\n    EVP_PKEY_CTX_free(ctx);\n    rb_str_set_len(sig, outlen);\n    return sig;\n}\n\n/*\n * call-seq:\n *    pkey.verify_raw(digest, signature, data [, options]) -> true or false\n *\n * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike\n * #verify, this method will not hash +data+ with +digest+ automatically.\n *\n * Returns +true+ if the signature is successfully verified, +false+ otherwise.\n * The caller must check the return value.\n *\n * See #sign_raw for the signing operation and an example code.\n *\n * Added in version 3.0. See also the man page EVP_PKEY_verify(3).\n *\n * +signature+::\n *   A String containing the signature to be verified.\n */\nstatic VALUE\nossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    VALUE digest, sig, data, options, md_holder;\n    const EVP_MD *md = NULL;\n    EVP_PKEY_CTX *ctx;\n    int state, ret;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"31\", &digest, &sig, &data, &options);\n    ossl_pkey_check_public_key(pkey);\n    if (!NIL_P(digest))\n        md = ossl_evp_md_fetch(digest, &md_holder);\n    StringValue(sig);\n    StringValue(data);\n\n    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);\n    if (!ctx)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n    if (EVP_PKEY_verify_init(ctx) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_verify_init\");\n    }\n    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_set_signature_md\");\n    }\n    if (!NIL_P(options)) {\n        pkey_ctx_apply_options(ctx, options, &state);\n        if (state) {\n            EVP_PKEY_CTX_free(ctx);\n            rb_jump_tag(state);\n        }\n    }\n    ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig),\n                          RSTRING_LEN(sig),\n                          (unsigned char *)RSTRING_PTR(data),\n                          RSTRING_LEN(data));\n    EVP_PKEY_CTX_free(ctx);\n    if (ret < 0)\n        ossl_raise(ePKeyError, \"EVP_PKEY_verify\");\n\n    if (ret)\n        return Qtrue;\n    else {\n        ossl_clear_error();\n        return Qfalse;\n    }\n}\n\n/*\n * call-seq:\n *    pkey.verify_recover(digest, signature [, options]) -> string\n *\n * Recovers the signed data from +signature+ using a public key +pkey+. Not all\n * signature algorithms support this operation.\n *\n * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3).\n *\n * +signature+::\n *   A String containing the signature to be verified.\n */\nstatic VALUE\nossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    VALUE digest, sig, options, out, md_holder;\n    const EVP_MD *md = NULL;\n    EVP_PKEY_CTX *ctx;\n    int state;\n    size_t outlen;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"21\", &digest, &sig, &options);\n    ossl_pkey_check_public_key(pkey);\n    if (!NIL_P(digest))\n        md = ossl_evp_md_fetch(digest, &md_holder);\n    StringValue(sig);\n\n    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);\n    if (!ctx)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n    if (EVP_PKEY_verify_recover_init(ctx) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_verify_recover_init\");\n    }\n    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_set_signature_md\");\n    }\n    if (!NIL_P(options)) {\n        pkey_ctx_apply_options(ctx, options, &state);\n        if (state) {\n            EVP_PKEY_CTX_free(ctx);\n            rb_jump_tag(state);\n        }\n    }\n    if (EVP_PKEY_verify_recover(ctx, NULL, &outlen,\n                                (unsigned char *)RSTRING_PTR(sig),\n                                RSTRING_LEN(sig)) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_verify_recover\");\n    }\n    out = ossl_str_new(NULL, (long)outlen, &state);\n    if (state) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_jump_tag(state);\n    }\n    if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen,\n                                (unsigned char *)RSTRING_PTR(sig),\n                                RSTRING_LEN(sig)) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_verify_recover\");\n    }\n    EVP_PKEY_CTX_free(ctx);\n    rb_str_set_len(out, outlen);\n    return out;\n}\n\n/*\n * call-seq:\n *    pkey.derive(peer_pkey) -> string\n *\n * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain\n * the private components, _peer_pkey_ must contain the public components.\n */\nstatic VALUE\nossl_pkey_derive(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey, *peer_pkey;\n    EVP_PKEY_CTX *ctx;\n    VALUE peer_pkey_obj, str;\n    size_t keylen;\n    int state;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"1\", &peer_pkey_obj);\n    GetPKey(peer_pkey_obj, peer_pkey);\n\n    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);\n    if (!ctx)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n    if (EVP_PKEY_derive_init(ctx) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_derive_init\");\n    }\n    if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_derive_set_peer\");\n    }\n    if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_derive\");\n    }\n    if (keylen > LONG_MAX) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_raise(ePKeyError, \"derived key would be too large\");\n    }\n    str = ossl_str_new(NULL, (long)keylen, &state);\n    if (state) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_jump_tag(state);\n    }\n    if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_derive\");\n    }\n    EVP_PKEY_CTX_free(ctx);\n    rb_str_set_len(str, keylen);\n    return str;\n}\n\n/*\n * call-seq:\n *    pkey.encrypt(data [, options]) -> string\n *\n * Performs a public key encryption operation using +pkey+.\n *\n * See #decrypt for the reverse operation.\n *\n * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3).\n *\n * +data+::\n *   A String to be encrypted.\n * +options+::\n *   A Hash that contains algorithm specific control operations to \\OpenSSL.\n *   See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.\n *\n * Example:\n *   pkey = OpenSSL::PKey.generate_key(\"RSA\", rsa_keygen_bits: 2048)\n *   data = \"secret data\"\n *   encrypted = pkey.encrypt(data, rsa_padding_mode: \"oaep\")\n *   decrypted = pkey.decrypt(data, rsa_padding_mode: \"oaep\")\n *   p decrypted #=> \"secret data\"\n */\nstatic VALUE\nossl_pkey_encrypt(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    EVP_PKEY_CTX *ctx;\n    VALUE data, options, str;\n    size_t outlen;\n    int state;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"11\", &data, &options);\n    StringValue(data);\n\n    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);\n    if (!ctx)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n    if (EVP_PKEY_encrypt_init(ctx) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_encrypt_init\");\n    }\n    if (!NIL_P(options)) {\n        pkey_ctx_apply_options(ctx, options, &state);\n        if (state) {\n            EVP_PKEY_CTX_free(ctx);\n            rb_jump_tag(state);\n        }\n    }\n    if (EVP_PKEY_encrypt(ctx, NULL, &outlen,\n                         (unsigned char *)RSTRING_PTR(data),\n                         RSTRING_LEN(data)) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_encrypt\");\n    }\n    if (outlen > LONG_MAX) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_raise(ePKeyError, \"encrypted data would be too large\");\n    }\n    str = ossl_str_new(NULL, (long)outlen, &state);\n    if (state) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_jump_tag(state);\n    }\n    if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,\n                         (unsigned char *)RSTRING_PTR(data),\n                         RSTRING_LEN(data)) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_encrypt\");\n    }\n    EVP_PKEY_CTX_free(ctx);\n    rb_str_set_len(str, outlen);\n    return str;\n}\n\n/*\n * call-seq:\n *    pkey.decrypt(data [, options]) -> string\n *\n * Performs a public key decryption operation using +pkey+.\n *\n * See #encrypt for a description of the parameters and an example.\n *\n * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3).\n */\nstatic VALUE\nossl_pkey_decrypt(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    EVP_PKEY_CTX *ctx;\n    VALUE data, options, str;\n    size_t outlen;\n    int state;\n\n    GetPKey(self, pkey);\n    rb_scan_args(argc, argv, \"11\", &data, &options);\n    StringValue(data);\n\n    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);\n    if (!ctx)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n    if (EVP_PKEY_decrypt_init(ctx) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_decrypt_init\");\n    }\n    if (!NIL_P(options)) {\n        pkey_ctx_apply_options(ctx, options, &state);\n        if (state) {\n            EVP_PKEY_CTX_free(ctx);\n            rb_jump_tag(state);\n        }\n    }\n    if (EVP_PKEY_decrypt(ctx, NULL, &outlen,\n                         (unsigned char *)RSTRING_PTR(data),\n                         RSTRING_LEN(data)) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_decrypt\");\n    }\n    if (outlen > LONG_MAX) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_raise(ePKeyError, \"decrypted data would be too large\");\n    }\n    str = ossl_str_new(NULL, (long)outlen, &state);\n    if (state) {\n        EVP_PKEY_CTX_free(ctx);\n        rb_jump_tag(state);\n    }\n    if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,\n                         (unsigned char *)RSTRING_PTR(data),\n                         RSTRING_LEN(data)) <= 0) {\n        EVP_PKEY_CTX_free(ctx);\n        ossl_raise(ePKeyError, \"EVP_PKEY_decrypt\");\n    }\n    EVP_PKEY_CTX_free(ctx);\n    rb_str_set_len(str, outlen);\n    return str;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_pkey(void)\n{\n#undef rb_intern\n    /* Document-module: OpenSSL::PKey\n     *\n     * == Asymmetric Public Key Algorithms\n     *\n     * Asymmetric public key algorithms solve the problem of establishing and\n     * sharing secret keys to en-/decrypt messages. The key in such an\n     * algorithm consists of two parts: a public key that may be distributed\n     * to others and a private key that needs to remain secret.\n     *\n     * Messages encrypted with a public key can only be decrypted by\n     * recipients that are in possession of the associated private key.\n     * Since public key algorithms are considerably slower than symmetric\n     * key algorithms (cf. OpenSSL::Cipher) they are often used to establish\n     * a symmetric key shared between two parties that are in possession of\n     * each other's public key.\n     *\n     * Asymmetric algorithms offer a lot of nice features that are used in a\n     * lot of different areas. A very common application is the creation and\n     * validation of digital signatures. To sign a document, the signatory\n     * generally uses a message digest algorithm (cf. OpenSSL::Digest) to\n     * compute a digest of the document that is then encrypted (i.e. signed)\n     * using the private key. Anyone in possession of the public key may then\n     * verify the signature by computing the message digest of the original\n     * document on their own, decrypting the signature using the signatory's\n     * public key and comparing the result to the message digest they\n     * previously computed. The signature is valid if and only if the\n     * decrypted signature is equal to this message digest.\n     *\n     * The PKey module offers support for three popular public/private key\n     * algorithms:\n     * * RSA (OpenSSL::PKey::RSA)\n     * * DSA (OpenSSL::PKey::DSA)\n     * * Elliptic Curve Cryptography (OpenSSL::PKey::EC)\n     * Each of these implementations is in fact a sub-class of the abstract\n     * PKey class which offers the interface for supporting digital signatures\n     * in the form of PKey#sign and PKey#verify.\n     *\n     * == Diffie-Hellman Key Exchange\n     *\n     * Finally PKey also features OpenSSL::PKey::DH, an implementation of\n     * the Diffie-Hellman key exchange protocol based on discrete logarithms\n     * in finite fields, the same basis that DSA is built on.\n     * The Diffie-Hellman protocol can be used to exchange (symmetric) keys\n     * over insecure channels without needing any prior joint knowledge\n     * between the participating parties. As the security of DH demands\n     * relatively long \"public keys\" (i.e. the part that is overtly\n     * transmitted between participants) DH tends to be quite slow. If\n     * security or speed is your primary concern, OpenSSL::PKey::EC offers\n     * another implementation of the Diffie-Hellman protocol.\n     *\n     */\n    mPKey = rb_define_module_under(mOSSL, \"PKey\");\n\n    /* Document-class: OpenSSL::PKey::PKeyError\n     *\n     * Raised when errors occur during PKey#sign or PKey#verify.\n     *\n     * Before version 4.0.0, OpenSSL::PKey::PKeyError had the following\n     * subclasses. These subclasses have been removed and the constants are\n     * now defined as aliases of OpenSSL::PKey::PKeyError.\n     *\n     * * OpenSSL::PKey::DHError\n     * * OpenSSL::PKey::DSAError\n     * * OpenSSL::PKey::ECError\n     * * OpenSSL::PKey::RSAError\n     */\n    ePKeyError = rb_define_class_under(mPKey, \"PKeyError\", eOSSLError);\n\n    /* Document-class: OpenSSL::PKey::PKey\n     *\n     * An abstract class that bundles signature creation (PKey#sign) and\n     * validation (PKey#verify) that is common to all implementations except\n     * OpenSSL::PKey::DH\n     * * OpenSSL::PKey::RSA\n     * * OpenSSL::PKey::DSA\n     * * OpenSSL::PKey::EC\n     */\n    cPKey = rb_define_class_under(mPKey, \"PKey\", rb_cObject);\n\n    rb_define_module_function(mPKey, \"read\", ossl_pkey_new_from_data, -1);\n    rb_define_module_function(mPKey, \"generate_parameters\", ossl_pkey_s_generate_parameters, -1);\n    rb_define_module_function(mPKey, \"generate_key\", ossl_pkey_s_generate_key, -1);\n    rb_define_module_function(mPKey, \"new_raw_private_key\", ossl_pkey_new_raw_private_key, 2);\n    rb_define_module_function(mPKey, \"new_raw_public_key\", ossl_pkey_new_raw_public_key, 2);\n\n    rb_define_alloc_func(cPKey, ossl_pkey_alloc);\n    rb_define_method(cPKey, \"initialize\", ossl_pkey_initialize, 0);\n#ifdef HAVE_EVP_PKEY_DUP\n    rb_define_method(cPKey, \"initialize_copy\", ossl_pkey_initialize_copy, 1);\n#else\n    rb_undef_method(cPKey, \"initialize_copy\");\n#endif\n    rb_define_method(cPKey, \"oid\", ossl_pkey_oid, 0);\n    rb_define_method(cPKey, \"inspect\", ossl_pkey_inspect, 0);\n    rb_define_method(cPKey, \"to_text\", ossl_pkey_to_text, 0);\n    rb_define_method(cPKey, \"private_to_der\", ossl_pkey_private_to_der, -1);\n    rb_define_method(cPKey, \"private_to_pem\", ossl_pkey_private_to_pem, -1);\n    rb_define_method(cPKey, \"public_to_der\", ossl_pkey_public_to_der, 0);\n    rb_define_method(cPKey, \"public_to_pem\", ossl_pkey_public_to_pem, 0);\n    rb_define_method(cPKey, \"raw_private_key\", ossl_pkey_raw_private_key, 0);\n    rb_define_method(cPKey, \"raw_public_key\", ossl_pkey_raw_public_key, 0);\n    rb_define_method(cPKey, \"compare?\", ossl_pkey_compare, 1);\n\n    rb_define_method(cPKey, \"sign\", ossl_pkey_sign, -1);\n    rb_define_method(cPKey, \"verify\", ossl_pkey_verify, -1);\n    rb_define_method(cPKey, \"sign_raw\", ossl_pkey_sign_raw, -1);\n    rb_define_method(cPKey, \"verify_raw\", ossl_pkey_verify_raw, -1);\n    rb_define_method(cPKey, \"verify_recover\", ossl_pkey_verify_recover, -1);\n    rb_define_method(cPKey, \"derive\", ossl_pkey_derive, -1);\n    rb_define_method(cPKey, \"encrypt\", ossl_pkey_encrypt, -1);\n    rb_define_method(cPKey, \"decrypt\", ossl_pkey_decrypt, -1);\n\n    id_private_q = rb_intern(\"private?\");\n\n    /*\n     * INIT rsa, dsa, dh, ec\n     */\n    Init_ossl_rsa();\n    Init_ossl_dsa();\n    Init_ossl_dh();\n    Init_ossl_ec();\n}\n"
  },
  {
    "path": "ext/openssl/ossl_pkey.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(OSSL_PKEY_H)\n#define OSSL_PKEY_H\n\nextern VALUE mPKey;\nextern VALUE cPKey;\nextern VALUE ePKeyError;\nextern const rb_data_type_t ossl_evp_pkey_type;\n\n/* For ENGINE */\n#define OSSL_PKEY_SET_PRIVATE(obj) rb_ivar_set((obj), rb_intern(\"private\"), Qtrue)\n#define OSSL_PKEY_IS_PRIVATE(obj)  (rb_attr_get((obj), rb_intern(\"private\")) == Qtrue)\n\n#define GetPKey(obj, pkey) do {\\\n    TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \\\n    if (!(pkey)) { \\\n        rb_raise(rb_eRuntimeError, \"PKEY wasn't initialized!\");\\\n    } \\\n} while (0)\n\n/* Takes ownership of the EVP_PKEY */\nVALUE ossl_pkey_wrap(EVP_PKEY *);\nvoid ossl_pkey_check_public_key(const EVP_PKEY *);\nEVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);\nEVP_PKEY *GetPKeyPtr(VALUE);\nEVP_PKEY *DupPKeyPtr(VALUE);\nEVP_PKEY *GetPrivPKeyPtr(VALUE);\n\n/*\n * Serializes _self_ in X.509 SubjectPublicKeyInfo format and returns the\n * resulting String. Sub-classes use this when overriding #to_der.\n */\nVALUE ossl_pkey_export_spki(VALUE self, int to_der);\n/*\n * Serializes the private key _self_ in the traditional private key format\n * and returns the resulting String. Sub-classes use this when overriding\n * #to_der.\n */\nVALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self,\n                                   int to_der);\n\nvoid Init_ossl_pkey(void);\n\n/*\n * RSA\n */\nextern VALUE cRSA;\nvoid Init_ossl_rsa(void);\n\n/*\n * DSA\n */\nextern VALUE cDSA;\nvoid Init_ossl_dsa(void);\n\n/*\n * DH\n */\nextern VALUE cDH;\nvoid Init_ossl_dh(void);\n\n/*\n * EC\n */\nextern VALUE cEC;\nvoid Init_ossl_ec(void);\n\n#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get)          \\\n/*                                                                      \\\n *  call-seq:                                                           \\\n *     _keytype##.##_name -> aBN                                        \\\n */                                                                     \\\nstatic VALUE ossl_##_keytype##_get_##_name(VALUE self)                  \\\n{                                                                       \\\n        const _type *obj;                                               \\\n        const BIGNUM *bn;                                               \\\n                                                                        \\\n        Get##_type(self, obj);                                          \\\n        _get;                                                           \\\n        if (bn == NULL)                                                 \\\n                return Qnil;                                            \\\n        return ossl_bn_new(bn);                                         \\\n}\n\n#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3)   \\\n        OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1,                   \\\n                _type##_get0_##_group(obj, &bn, NULL, NULL))            \\\n        OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2,                   \\\n                _type##_get0_##_group(obj, NULL, &bn, NULL))            \\\n        OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3,                   \\\n                _type##_get0_##_group(obj, NULL, NULL, &bn))\n\n#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2)       \\\n        OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1,                   \\\n                _type##_get0_##_group(obj, &bn, NULL))                  \\\n        OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2,                   \\\n                _type##_get0_##_group(obj, NULL, &bn))\n\n#ifndef OSSL_HAVE_IMMUTABLE_PKEY\n#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)   \\\n/*                                                                      \\\n *  call-seq:                                                           \\\n *     _keytype##.set_##_group(a1, a2, a3) -> self                      \\\n */                                                                     \\\nstatic VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \\\n{                                                                       \\\n        _type *obj;                                                     \\\n        BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\\\n        BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\\\n        BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\\\n                                                                        \\\n        Get##_type(self, obj);                                          \\\n        if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) ||                  \\\n            (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) ||                  \\\n            (orig_bn3 && !(bn3 = BN_dup(orig_bn3)))) {                  \\\n                BN_clear_free(bn1);                                     \\\n                BN_clear_free(bn2);                                     \\\n                BN_clear_free(bn3);                                     \\\n                ossl_raise(ePKeyError, \"BN_dup\");                       \\\n        }                                                               \\\n                                                                        \\\n        if (!_type##_set0_##_group(obj, bn1, bn2, bn3)) {               \\\n                BN_clear_free(bn1);                                     \\\n                BN_clear_free(bn2);                                     \\\n                BN_clear_free(bn3);                                     \\\n                ossl_raise(ePKeyError, #_type\"_set0_\"#_group);          \\\n        }                                                               \\\n        return self;                                                    \\\n}\n\n#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)       \\\n/*                                                                      \\\n *  call-seq:                                                           \\\n *     _keytype##.set_##_group(a1, a2) -> self                          \\\n */                                                                     \\\nstatic VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \\\n{                                                                       \\\n        _type *obj;                                                     \\\n        BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\\\n        BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\\\n                                                                        \\\n        Get##_type(self, obj);                                          \\\n        if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) ||                  \\\n            (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) {                  \\\n                BN_clear_free(bn1);                                     \\\n                BN_clear_free(bn2);                                     \\\n                ossl_raise(ePKeyError, \"BN_dup\");                       \\\n        }                                                               \\\n                                                                        \\\n        if (!_type##_set0_##_group(obj, bn1, bn2)) {                    \\\n                BN_clear_free(bn1);                                     \\\n                BN_clear_free(bn2);                                     \\\n                ossl_raise(ePKeyError, #_type\"_set0_\"#_group);          \\\n        }                                                               \\\n        return self;                                                    \\\n}\n#else\n#define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)   \\\nstatic VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2, VALUE v3) \\\n{                                                                       \\\n        rb_raise(ePKeyError,                                            \\\n                 #_keytype\"#set_\"#_group\"= is incompatible with OpenSSL 3.0\"); \\\n}\n\n#define OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)       \\\nstatic VALUE ossl_##_keytype##_set_##_group(VALUE self, VALUE v1, VALUE v2) \\\n{                                                                       \\\n        rb_raise(ePKeyError,                                            \\\n                 #_keytype\"#set_\"#_group\"= is incompatible with OpenSSL 3.0\"); \\\n}\n#endif\n\n#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3)          \\\n        OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3)   \\\n        OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)\n\n#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2)              \\\n        OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2)       \\\n        OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)\n\n#define DEF_OSSL_PKEY_BN(class, keytype, name)                          \\\n        rb_define_method((class), #name, ossl_##keytype##_get_##name, 0)\n\n#endif /* OSSL_PKEY_H */\n"
  },
  {
    "path": "ext/openssl/ossl_pkey_dh.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#if !defined(OPENSSL_NO_DH)\n\n#define GetPKeyDH(obj, pkey) do { \\\n    GetPKey((obj), (pkey)); \\\n    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) { /* PARANOIA? */ \\\n        ossl_raise(rb_eRuntimeError, \"THIS IS NOT A DH!\") ; \\\n    } \\\n} while (0)\n#define GetDH(obj, dh) do { \\\n    EVP_PKEY *_pkey; \\\n    GetPKeyDH((obj), _pkey); \\\n    (dh) = EVP_PKEY_get0_DH(_pkey); \\\n    if ((dh) == NULL) \\\n        ossl_raise(ePKeyError, \"failed to get DH from EVP_PKEY\"); \\\n} while (0)\n\n/*\n * Classes\n */\nVALUE cDH;\n\n/*\n * Private\n */\n/*\n * call-seq:\n *   DH.new -> dh\n *   DH.new(string) -> dh\n *   DH.new(size [, generator]) -> dh\n *\n * Creates a new instance of OpenSSL::PKey::DH.\n *\n * If called without arguments, an empty instance without any parameter or key\n * components is created. Use #set_pqg to manually set the parameters afterwards\n * (and optionally #set_key to set private and public key components).\n * This form is not compatible with OpenSSL 3.0 or later.\n *\n * If a String is given, tries to parse it as a DER- or PEM- encoded parameters.\n * See also OpenSSL::PKey.read which can parse keys of any kinds.\n *\n * The DH.new(size [, generator]) form is an alias of DH.generate.\n *\n * +string+::\n *   A String that contains the DER or PEM encoded key.\n * +size+::\n *   See DH.generate.\n * +generator+::\n *   See DH.generate.\n *\n * Examples:\n *   # Creating an instance from scratch\n *   # Note that this is deprecated and will result in ArgumentError when\n *   # using OpenSSL 3.0 or later.\n *   dh = OpenSSL::PKey::DH.new\n *   dh.set_pqg(bn_p, nil, bn_g)\n *\n *   # Generating a parameters and a key pair\n *   dh = OpenSSL::PKey::DH.new(2048) # An alias of OpenSSL::PKey::DH.generate(2048)\n *\n *   # Reading DH parameters from a PEM-encoded string\n *   dh_params = OpenSSL::PKey::DH.new(File.read('parameters.pem')) # loads parameters only\n *   dh = OpenSSL::PKey.generate_key(dh_params) # generates a key pair\n */\nstatic VALUE\nossl_dh_initialize(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    int type;\n    DH *dh;\n    BIO *in = NULL;\n    VALUE arg;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n\n    /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */\n    if (rb_scan_args(argc, argv, \"01\", &arg) == 0) {\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n        rb_raise(rb_eArgError, \"OpenSSL::PKey::DH.new cannot be called \" \\\n                 \"without arguments; pkeys are immutable with OpenSSL 3.0\");\n#else\n        dh = DH_new();\n        if (!dh)\n            ossl_raise(ePKeyError, \"DH_new\");\n        goto legacy;\n#endif\n    }\n\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n\n    /*\n     * On OpenSSL <= 1.1.1 and current versions of LibreSSL, the generic\n     * routine does not support DER-encoded parameters\n     */\n    dh = d2i_DHparams_bio(in, NULL);\n    if (dh)\n        goto legacy;\n    OSSL_BIO_reset(in);\n\n    pkey = ossl_pkey_read_generic(in, Qnil);\n    BIO_free(in);\n    if (!pkey)\n        ossl_raise(ePKeyError, \"could not parse pkey\");\n\n    type = EVP_PKEY_base_id(pkey);\n    if (type != EVP_PKEY_DH) {\n        EVP_PKEY_free(pkey);\n        rb_raise(ePKeyError, \"incorrect pkey type: %s\", OBJ_nid2sn(type));\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n\n  legacy:\n    BIO_free(in);\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {\n        EVP_PKEY_free(pkey);\n        DH_free(dh);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_DH\");\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n}\n\n#ifndef HAVE_EVP_PKEY_DUP\n/* :nodoc: */\nstatic VALUE\nossl_dh_initialize_copy(VALUE self, VALUE other)\n{\n    EVP_PKEY *pkey;\n    DH *dh, *dh_other;\n    const BIGNUM *pub, *priv;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n    GetDH(other, dh_other);\n\n    dh = DHparams_dup(dh_other);\n    if (!dh)\n        ossl_raise(ePKeyError, \"DHparams_dup\");\n\n    DH_get0_key(dh_other, &pub, &priv);\n    if (pub) {\n        BIGNUM *pub2 = BN_dup(pub);\n        BIGNUM *priv2 = BN_dup(priv);\n\n        if (!pub2 || (priv && !priv2)) {\n            BN_clear_free(pub2);\n            BN_clear_free(priv2);\n            ossl_raise(ePKeyError, \"BN_dup\");\n        }\n        DH_set0_key(dh, pub2, priv2);\n    }\n\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {\n        EVP_PKEY_free(pkey);\n        DH_free(dh);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_DH\");\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n}\n#endif\n\n/*\n *  call-seq:\n *     dh.public? -> true | false\n *\n * Indicates whether this DH instance has a public key associated with it or\n * not. The public key may be retrieved with DH#pub_key.\n */\nstatic VALUE\nossl_dh_is_public(VALUE self)\n{\n    OSSL_3_const DH *dh;\n    const BIGNUM *bn;\n\n    GetDH(self, dh);\n    DH_get0_key(dh, &bn, NULL);\n\n    return bn ? Qtrue : Qfalse;\n}\n\n/*\n *  call-seq:\n *     dh.private? -> true | false\n *\n * Indicates whether this DH instance has a private key associated with it or\n * not. The private key may be retrieved with DH#priv_key.\n */\nstatic VALUE\nossl_dh_is_private(VALUE self)\n{\n    OSSL_3_const DH *dh;\n    const BIGNUM *bn;\n\n    GetDH(self, dh);\n    DH_get0_key(dh, NULL, &bn);\n\n#if !defined(OPENSSL_NO_ENGINE)\n    return (bn || DH_get0_engine((DH *)dh)) ? Qtrue : Qfalse;\n#else\n    return bn ? Qtrue : Qfalse;\n#endif\n}\n\n/*\n *  call-seq:\n *     dh.export -> aString\n *     dh.to_pem -> aString\n *     dh.to_s -> aString\n *\n * Serializes the DH parameters to a PEM-encoding.\n *\n * Note that any existing per-session public/private keys will *not* get\n * encoded, just the Diffie-Hellman parameters will be encoded.\n *\n * PEM-encoded parameters will look like:\n *\n *   -----BEGIN DH PARAMETERS-----\n *   [...]\n *   -----END DH PARAMETERS-----\n *\n * See also #public_to_pem (X.509 SubjectPublicKeyInfo) and\n * #private_to_pem (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for\n * serialization with the private or public key components.\n */\nstatic VALUE\nossl_dh_export(VALUE self)\n{\n    OSSL_3_const DH *dh;\n    BIO *out;\n    VALUE str;\n\n    GetDH(self, dh);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(ePKeyError, NULL);\n    }\n    if (!PEM_write_bio_DHparams(out, dh)) {\n        BIO_free(out);\n        ossl_raise(ePKeyError, NULL);\n    }\n    str = ossl_membio2str(out);\n\n    return str;\n}\n\n/*\n *  call-seq:\n *     dh.to_der -> aString\n *\n * Serializes the DH parameters to a DER-encoding\n *\n * Note that any existing per-session public/private keys will *not* get\n * encoded, just the Diffie-Hellman parameters will be encoded.\n *\n * See also #public_to_der (X.509 SubjectPublicKeyInfo) and\n * #private_to_der (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for\n * serialization with the private or public key components.\n */\nstatic VALUE\nossl_dh_to_der(VALUE self)\n{\n    OSSL_3_const DH *dh;\n    unsigned char *p;\n    long len;\n    VALUE str;\n\n    GetDH(self, dh);\n    if((len = i2d_DHparams(dh, NULL)) <= 0)\n        ossl_raise(ePKeyError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d_DHparams(dh, &p) < 0)\n        ossl_raise(ePKeyError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n *  call-seq:\n *     dh.params_ok? -> true | false\n *\n * Validates the Diffie-Hellman parameters associated with this instance.\n * It checks whether a safe prime and a suitable generator are used. If this\n * is not the case, +false+ is returned.\n *\n * See also the man page EVP_PKEY_param_check(3).\n */\nstatic VALUE\nossl_dh_check_params(VALUE self)\n{\n    int ret;\n#ifdef HAVE_EVP_PKEY_CHECK\n    EVP_PKEY *pkey;\n    EVP_PKEY_CTX *pctx;\n\n    GetPKey(self, pkey);\n    pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);\n    if (!pctx)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n    ret = EVP_PKEY_param_check(pctx);\n    EVP_PKEY_CTX_free(pctx);\n#else\n    DH *dh;\n    int codes;\n\n    GetDH(self, dh);\n    ret = DH_check(dh, &codes) == 1 && codes == 0;\n#endif\n\n    if (ret == 1)\n        return Qtrue;\n    else {\n        /* DH_check_ex() will put error entry on failure */\n        ossl_clear_error();\n        return Qfalse;\n    }\n}\n\n/*\n * Document-method: OpenSSL::PKey::DH#set_pqg\n * call-seq:\n *   dh.set_pqg(p, q, g) -> self\n *\n * Sets _p_, _q_, _g_ to the DH instance.\n */\nOSSL_PKEY_BN_DEF3(dh, DH, pqg, p, q, g)\n/*\n * Document-method: OpenSSL::PKey::DH#set_key\n * call-seq:\n *   dh.set_key(pub_key, priv_key) -> self\n *\n * Sets _pub_key_ and _priv_key_ for the DH instance. _priv_key_ may be +nil+.\n */\nOSSL_PKEY_BN_DEF2(dh, DH, key, pub_key, priv_key)\n\n/*\n * INIT\n */\nvoid\nInit_ossl_dh(void)\n{\n    /* Document-class: OpenSSL::PKey::DH\n     *\n     * An implementation of the Diffie-Hellman key exchange protocol based on\n     * discrete logarithms in finite fields, the same basis that DSA is built\n     * on.\n     *\n     * === Accessor methods for the Diffie-Hellman parameters\n     * DH#p::\n     *   The prime (an OpenSSL::BN) of the Diffie-Hellman parameters.\n     * DH#g::\n     *   The generator (an OpenSSL::BN) g of the Diffie-Hellman parameters.\n     * DH#pub_key::\n     *   The per-session public key (an OpenSSL::BN) matching the private key.\n     *   This needs to be passed to DH#compute_key.\n     * DH#priv_key::\n     *   The per-session private key, an OpenSSL::BN.\n     *\n     * === Example of a key exchange\n     *   # you may send the parameters (der) and own public key (pub1) publicly\n     *   # to the participating party\n     *   dh1 = OpenSSL::PKey::DH.new(2048)\n     *   der = dh1.to_der\n     *   pub1 = dh1.pub_key\n     *\n     *   # the other party generates its per-session key pair\n     *   dhparams = OpenSSL::PKey::DH.new(der)\n     *   dh2 = OpenSSL::PKey.generate_key(dhparams)\n     *   pub2 = dh2.pub_key\n     *\n     *   symm_key1 = dh1.compute_key(pub2)\n     *   symm_key2 = dh2.compute_key(pub1)\n     *   puts symm_key1 == symm_key2 # => true\n     */\n    cDH = rb_define_class_under(mPKey, \"DH\", cPKey);\n    rb_define_method(cDH, \"initialize\", ossl_dh_initialize, -1);\n#ifndef HAVE_EVP_PKEY_DUP\n    rb_define_method(cDH, \"initialize_copy\", ossl_dh_initialize_copy, 1);\n#endif\n    rb_define_method(cDH, \"public?\", ossl_dh_is_public, 0);\n    rb_define_method(cDH, \"private?\", ossl_dh_is_private, 0);\n    rb_define_method(cDH, \"export\", ossl_dh_export, 0);\n    rb_define_alias(cDH, \"to_pem\", \"export\");\n    rb_define_alias(cDH, \"to_s\", \"export\");\n    rb_define_method(cDH, \"to_der\", ossl_dh_to_der, 0);\n    rb_define_method(cDH, \"params_ok?\", ossl_dh_check_params, 0);\n\n    DEF_OSSL_PKEY_BN(cDH, dh, p);\n    DEF_OSSL_PKEY_BN(cDH, dh, q);\n    DEF_OSSL_PKEY_BN(cDH, dh, g);\n    DEF_OSSL_PKEY_BN(cDH, dh, pub_key);\n    DEF_OSSL_PKEY_BN(cDH, dh, priv_key);\n    rb_define_method(cDH, \"set_pqg\", ossl_dh_set_pqg, 3);\n    rb_define_method(cDH, \"set_key\", ossl_dh_set_key, 2);\n}\n\n#else /* defined NO_DH */\nvoid\nInit_ossl_dh(void)\n{\n}\n#endif /* NO_DH */\n"
  },
  {
    "path": "ext/openssl/ossl_pkey_dsa.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#if !defined(OPENSSL_NO_DSA)\n\n#define GetPKeyDSA(obj, pkey) do { \\\n    GetPKey((obj), (pkey)); \\\n    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { /* PARANOIA? */ \\\n        ossl_raise(rb_eRuntimeError, \"THIS IS NOT A DSA!\"); \\\n    } \\\n} while (0)\n#define GetDSA(obj, dsa) do { \\\n    EVP_PKEY *_pkey; \\\n    GetPKeyDSA((obj), _pkey); \\\n    (dsa) = EVP_PKEY_get0_DSA(_pkey); \\\n    if ((dsa) == NULL) \\\n        ossl_raise(ePKeyError, \"failed to get DSA from EVP_PKEY\"); \\\n} while (0)\n\nstatic inline int\nDSA_HAS_PRIVATE(OSSL_3_const DSA *dsa)\n{\n    const BIGNUM *bn;\n    DSA_get0_key(dsa, NULL, &bn);\n    return !!bn;\n}\n\nstatic inline int\nDSA_PRIVATE(VALUE obj, OSSL_3_const DSA *dsa)\n{\n    return DSA_HAS_PRIVATE(dsa) || OSSL_PKEY_IS_PRIVATE(obj);\n}\n\n/*\n * Classes\n */\nVALUE cDSA;\n\n/*\n * Private\n */\n/*\n *  call-seq:\n *    DSA.new -> dsa\n *    DSA.new(string [, pass]) -> dsa\n *    DSA.new(size) -> dsa\n *\n * Creates a new DSA instance by reading an existing key from _string_.\n *\n * If called without arguments, creates a new instance with no key components\n * set. They can be set individually by #set_pqg and #set_key.\n * This form is not compatible with OpenSSL 3.0 or later.\n *\n * If called with a String, tries to parse as DER or PEM encoding of a \\DSA key.\n * See also OpenSSL::PKey.read which can parse keys of any kinds.\n *\n * If called with a number, generates random parameters and a key pair. This\n * form works as an alias of DSA.generate.\n *\n * +string+::\n *   A String that contains a DER or PEM encoded key.\n * +pass+::\n *   A String that contains an optional password.\n * +size+::\n *   See DSA.generate.\n *\n * Examples:\n *   p OpenSSL::PKey::DSA.new(1024)\n *   #=> #<OpenSSL::PKey::DSA:0x000055a8d6025bf0 oid=DSA>\n *\n *   p OpenSSL::PKey::DSA.new(File.read('dsa.pem'))\n *   #=> #<OpenSSL::PKey::DSA:0x000055555d6b8110 oid=DSA>\n *\n *   p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword')\n *   #=> #<OpenSSL::PKey::DSA:0x0000556f973c40b8 oid=DSA>\n */\nstatic VALUE\nossl_dsa_initialize(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    DSA *dsa;\n    BIO *in = NULL;\n    VALUE arg, pass;\n    int type;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n\n    /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */\n    rb_scan_args(argc, argv, \"02\", &arg, &pass);\n    if (argc == 0) {\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n        rb_raise(rb_eArgError, \"OpenSSL::PKey::DSA.new cannot be called \" \\\n                 \"without arguments; pkeys are immutable with OpenSSL 3.0\");\n#else\n        dsa = DSA_new();\n        if (!dsa)\n            ossl_raise(ePKeyError, \"DSA_new\");\n        goto legacy;\n#endif\n    }\n\n    pass = ossl_pem_passwd_value(pass);\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n\n    /* DER-encoded DSAPublicKey format isn't supported by the generic routine */\n    dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey,\n                                   PEM_STRING_DSA_PUBLIC,\n                                   in, NULL, NULL, NULL);\n    if (dsa)\n        goto legacy;\n    OSSL_BIO_reset(in);\n\n    pkey = ossl_pkey_read_generic(in, pass);\n    BIO_free(in);\n    if (!pkey)\n        ossl_raise(ePKeyError, \"Neither PUB key nor PRIV key\");\n\n    type = EVP_PKEY_base_id(pkey);\n    if (type != EVP_PKEY_DSA) {\n        EVP_PKEY_free(pkey);\n        rb_raise(ePKeyError, \"incorrect pkey type: %s\", OBJ_nid2sn(type));\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n\n  legacy:\n    BIO_free(in);\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {\n        EVP_PKEY_free(pkey);\n        DSA_free(dsa);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_DSA\");\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n}\n\n#ifndef HAVE_EVP_PKEY_DUP\n/* :nodoc: */\nstatic VALUE\nossl_dsa_initialize_copy(VALUE self, VALUE other)\n{\n    EVP_PKEY *pkey;\n    DSA *dsa, *dsa_new;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n    GetDSA(other, dsa);\n\n    dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey,\n                              (d2i_of_void *)d2i_DSAPrivateKey,\n                              (char *)dsa);\n    if (!dsa_new)\n        ossl_raise(ePKeyError, \"ASN1_dup\");\n\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {\n        EVP_PKEY_free(pkey);\n        DSA_free(dsa_new);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_DSA\");\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n\n    return self;\n}\n#endif\n\n/*\n *  call-seq:\n *    dsa.public? -> true | false\n *\n * Indicates whether this DSA instance has a public key associated with it or\n * not. The public key may be retrieved with DSA#public_key.\n */\nstatic VALUE\nossl_dsa_is_public(VALUE self)\n{\n    const DSA *dsa;\n    const BIGNUM *bn;\n\n    GetDSA(self, dsa);\n    DSA_get0_key(dsa, &bn, NULL);\n\n    return bn ? Qtrue : Qfalse;\n}\n\n/*\n *  call-seq:\n *    dsa.private? -> true | false\n *\n * Indicates whether this DSA instance has a private key associated with it or\n * not. The private key may be retrieved with DSA#private_key.\n */\nstatic VALUE\nossl_dsa_is_private(VALUE self)\n{\n    OSSL_3_const DSA *dsa;\n\n    GetDSA(self, dsa);\n\n    return DSA_PRIVATE(self, dsa) ? Qtrue : Qfalse;\n}\n\n/*\n *  call-seq:\n *    dsa.export([cipher, password]) -> aString\n *    dsa.to_pem([cipher, password]) -> aString\n *    dsa.to_s([cipher, password]) -> aString\n *\n * Serializes a private or public key to a PEM-encoding.\n *\n * [When the key contains public components only]\n *\n *   Serializes it into an X.509 SubjectPublicKeyInfo.\n *   The parameters _cipher_ and _password_ are ignored.\n *\n *   A PEM-encoded key will look like:\n *\n *     -----BEGIN PUBLIC KEY-----\n *     [...]\n *     -----END PUBLIC KEY-----\n *\n *   Consider using #public_to_pem instead. This serializes the key into an\n *   X.509 SubjectPublicKeyInfo regardless of whether it is a public key\n *   or a private key.\n *\n * [When the key contains private components, and no parameters are given]\n *\n *   Serializes it into a traditional \\OpenSSL DSAPrivateKey.\n *\n *   A PEM-encoded key will look like:\n *\n *     -----BEGIN DSA PRIVATE KEY-----\n *     [...]\n *     -----END DSA PRIVATE KEY-----\n *\n * [When the key contains private components, and _cipher_ and _password_ are given]\n *\n *   Serializes it into a traditional \\OpenSSL DSAPrivateKey and encrypts it in\n *   OpenSSL's traditional PEM encryption format.\n *   _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an\n *   instance of OpenSSL::Cipher.\n *\n *   An encrypted PEM-encoded key will look like:\n *\n *     -----BEGIN DSA PRIVATE KEY-----\n *     Proc-Type: 4,ENCRYPTED\n *     DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0\n *\n *     [...]\n *     -----END DSA PRIVATE KEY-----\n *\n *   Note that this format uses MD5 to derive the encryption key, and hence\n *   will not be available on FIPS-compliant systems.\n *\n * <b>This method is kept for compatibility.</b>\n * This should only be used when the traditional, non-standard \\OpenSSL format\n * is required.\n *\n * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem\n * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.\n */\nstatic VALUE\nossl_dsa_export(int argc, VALUE *argv, VALUE self)\n{\n    OSSL_3_const DSA *dsa;\n\n    GetDSA(self, dsa);\n    if (DSA_HAS_PRIVATE(dsa))\n        return ossl_pkey_export_traditional(argc, argv, self, 0);\n    else\n        return ossl_pkey_export_spki(self, 0);\n}\n\n/*\n *  call-seq:\n *    dsa.to_der -> aString\n *\n * Serializes a private or public key to a DER-encoding.\n *\n * See #to_pem for details.\n *\n * <b>This method is kept for compatibility.</b>\n * This should only be used when the traditional, non-standard \\OpenSSL format\n * is required.\n *\n * Consider using #public_to_der or #private_to_der instead.\n */\nstatic VALUE\nossl_dsa_to_der(VALUE self)\n{\n    OSSL_3_const DSA *dsa;\n\n    GetDSA(self, dsa);\n    if (DSA_HAS_PRIVATE(dsa))\n        return ossl_pkey_export_traditional(0, NULL, self, 1);\n    else\n        return ossl_pkey_export_spki(self, 1);\n}\n\n\n/*\n * Document-method: OpenSSL::PKey::DSA#set_pqg\n * call-seq:\n *   dsa.set_pqg(p, q, g) -> self\n *\n * Sets _p_, _q_, _g_ to the DSA instance.\n */\nOSSL_PKEY_BN_DEF3(dsa, DSA, pqg, p, q, g)\n/*\n * Document-method: OpenSSL::PKey::DSA#set_key\n * call-seq:\n *   dsa.set_key(pub_key, priv_key) -> self\n *\n * Sets _pub_key_ and _priv_key_ for the DSA instance. _priv_key_ may be +nil+.\n */\nOSSL_PKEY_BN_DEF2(dsa, DSA, key, pub_key, priv_key)\n\n/*\n * INIT\n */\nvoid\nInit_ossl_dsa(void)\n{\n    /* Document-class: OpenSSL::PKey::DSA\n     *\n     * DSA, the Digital Signature Algorithm, is specified in NIST's\n     * FIPS 186-3. It is an asymmetric public key algorithm that may be used\n     * similar to e.g. RSA.\n     */\n    cDSA = rb_define_class_under(mPKey, \"DSA\", cPKey);\n\n    rb_define_method(cDSA, \"initialize\", ossl_dsa_initialize, -1);\n#ifndef HAVE_EVP_PKEY_DUP\n    rb_define_method(cDSA, \"initialize_copy\", ossl_dsa_initialize_copy, 1);\n#endif\n\n    rb_define_method(cDSA, \"public?\", ossl_dsa_is_public, 0);\n    rb_define_method(cDSA, \"private?\", ossl_dsa_is_private, 0);\n    rb_define_method(cDSA, \"export\", ossl_dsa_export, -1);\n    rb_define_alias(cDSA, \"to_pem\", \"export\");\n    rb_define_alias(cDSA, \"to_s\", \"export\");\n    rb_define_method(cDSA, \"to_der\", ossl_dsa_to_der, 0);\n\n    DEF_OSSL_PKEY_BN(cDSA, dsa, p);\n    DEF_OSSL_PKEY_BN(cDSA, dsa, q);\n    DEF_OSSL_PKEY_BN(cDSA, dsa, g);\n    DEF_OSSL_PKEY_BN(cDSA, dsa, pub_key);\n    DEF_OSSL_PKEY_BN(cDSA, dsa, priv_key);\n    rb_define_method(cDSA, \"set_pqg\", ossl_dsa_set_pqg, 3);\n    rb_define_method(cDSA, \"set_key\", ossl_dsa_set_key, 2);\n}\n\n#else /* defined NO_DSA */\nvoid\nInit_ossl_dsa(void)\n{\n}\n#endif /* NO_DSA */\n"
  },
  {
    "path": "ext/openssl/ossl_pkey_ec.c",
    "content": "/*\n * Copyright (C) 2006-2007 Technorama Ltd. <oss-ruby@technorama.net>\n */\n\n#include \"ossl.h\"\n\n#if !defined(OPENSSL_NO_EC)\n\n#define EXPORT_PEM 0\n#define EXPORT_DER 1\n\nstatic const rb_data_type_t ossl_ec_group_type;\nstatic const rb_data_type_t ossl_ec_point_type;\n\n#define GetPKeyEC(obj, pkey) do { \\\n    GetPKey((obj), (pkey)); \\\n    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { \\\n        ossl_raise(rb_eRuntimeError, \"THIS IS NOT A EC PKEY!\"); \\\n    } \\\n} while (0)\n#define GetEC(obj, key) do { \\\n    EVP_PKEY *_pkey; \\\n    GetPKeyEC(obj, _pkey); \\\n    (key) = EVP_PKEY_get0_EC_KEY(_pkey); \\\n    if ((key) == NULL) \\\n        ossl_raise(ePKeyError, \"failed to get EC_KEY from EVP_PKEY\"); \\\n} while (0)\n\n#define GetECGroup(obj, group) do { \\\n    TypedData_Get_Struct(obj, EC_GROUP, &ossl_ec_group_type, group); \\\n    if ((group) == NULL) \\\n        ossl_raise(eEC_GROUP, \"EC_GROUP is not initialized\"); \\\n} while (0)\n\n#define GetECPoint(obj, point) do { \\\n    TypedData_Get_Struct(obj, EC_POINT, &ossl_ec_point_type, point); \\\n    if ((point) == NULL) \\\n        ossl_raise(eEC_POINT, \"EC_POINT is not initialized\"); \\\n} while (0)\n#define GetECPointGroup(obj, group) do { \\\n    VALUE _group = rb_attr_get(obj, id_i_group); \\\n    GetECGroup(_group, group); \\\n} while (0)\n\nVALUE cEC;\nstatic VALUE cEC_GROUP;\nstatic VALUE eEC_GROUP;\nstatic VALUE cEC_POINT;\nstatic VALUE eEC_POINT;\n\nstatic VALUE sym_GFp, sym_GF2m;\nstatic VALUE sym_uncompressed, sym_compressed, sym_hybrid;\n\nstatic ID id_i_group;\n\nstatic VALUE ec_group_new(const EC_GROUP *group);\nstatic VALUE ec_point_new(const EC_POINT *point, const EC_GROUP *group);\n\n/*\n * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String\n * representing an OID.\n */\nstatic EC_KEY *\nec_key_new_from_group(VALUE arg)\n{\n    EC_KEY *ec;\n\n    if (rb_obj_is_kind_of(arg, cEC_GROUP)) {\n        EC_GROUP *group;\n\n        GetECGroup(arg, group);\n        if (!(ec = EC_KEY_new()))\n            ossl_raise(ePKeyError, NULL);\n\n        if (!EC_KEY_set_group(ec, group)) {\n            EC_KEY_free(ec);\n            ossl_raise(ePKeyError, NULL);\n        }\n    } else {\n        int nid = OBJ_sn2nid(StringValueCStr(arg));\n\n        if (nid == NID_undef)\n            ossl_raise(ePKeyError, \"invalid curve name\");\n\n        if (!(ec = EC_KEY_new_by_curve_name(nid)))\n            ossl_raise(ePKeyError, NULL);\n\n        EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);\n        EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);\n    }\n\n    return ec;\n}\n\n/*\n *  call-seq:\n *     EC.generate(ec_group) -> ec\n *     EC.generate(string) -> ec\n *\n * Creates a new EC instance with a new random private and public key.\n */\nstatic VALUE\nossl_ec_key_s_generate(VALUE klass, VALUE arg)\n{\n    EVP_PKEY *pkey;\n    EC_KEY *ec;\n    VALUE obj;\n\n    obj = rb_obj_alloc(klass);\n\n    ec = ec_key_new_from_group(arg);\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {\n        EVP_PKEY_free(pkey);\n        EC_KEY_free(ec);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_EC_KEY\");\n    }\n    RTYPEDDATA_DATA(obj) = pkey;\n\n    if (!EC_KEY_generate_key(ec))\n        ossl_raise(ePKeyError, \"EC_KEY_generate_key\");\n\n    return obj;\n}\n\n/*\n * call-seq:\n *   OpenSSL::PKey::EC.new\n *   OpenSSL::PKey::EC.new(ec_key)\n *   OpenSSL::PKey::EC.new(ec_group)\n *   OpenSSL::PKey::EC.new(\"secp112r1\")\n *   OpenSSL::PKey::EC.new(pem_string [, pwd])\n *   OpenSSL::PKey::EC.new(der_string)\n *\n * Creates a new EC object from given arguments.\n */\nstatic VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    EC_KEY *ec;\n    BIO *in;\n    VALUE arg, pass;\n    int type;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n\n    rb_scan_args(argc, argv, \"02\", &arg, &pass);\n    if (NIL_P(arg)) {\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n        rb_raise(rb_eArgError, \"OpenSSL::PKey::EC.new cannot be called \" \\\n                 \"without arguments; pkeys are immutable with OpenSSL 3.0\");\n#else\n        if (!(ec = EC_KEY_new()))\n            ossl_raise(ePKeyError, \"EC_KEY_new\");\n        goto legacy;\n#endif\n    }\n    else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {\n        ec = ec_key_new_from_group(arg);\n        goto legacy;\n    }\n\n    pass = ossl_pem_passwd_value(pass);\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n\n    pkey = ossl_pkey_read_generic(in, pass);\n    BIO_free(in);\n    if (!pkey) {\n        ossl_clear_error();\n        ec = ec_key_new_from_group(arg);\n        goto legacy;\n    }\n\n    type = EVP_PKEY_base_id(pkey);\n    if (type != EVP_PKEY_EC) {\n        EVP_PKEY_free(pkey);\n        rb_raise(ePKeyError, \"incorrect pkey type: %s\", OBJ_nid2sn(type));\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n\n  legacy:\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {\n        EVP_PKEY_free(pkey);\n        EC_KEY_free(ec);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_EC_KEY\");\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n}\n\n#ifndef HAVE_EVP_PKEY_DUP\n/* :nodoc: */\nstatic VALUE\nossl_ec_key_initialize_copy(VALUE self, VALUE other)\n{\n    EVP_PKEY *pkey;\n    EC_KEY *ec, *ec_new;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n    GetEC(other, ec);\n\n    ec_new = EC_KEY_dup(ec);\n    if (!ec_new)\n        ossl_raise(ePKeyError, \"EC_KEY_dup\");\n\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) {\n        EC_KEY_free(ec_new);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_EC_KEY\");\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n\n    return self;\n}\n#endif\n\n/*\n * call-seq:\n *   key.group   => group\n *\n * Returns the EC::Group that the key is associated with. Modifying the returned\n * group does not affect _key_.\n */\nstatic VALUE\nossl_ec_key_get_group(VALUE self)\n{\n    OSSL_3_const EC_KEY *ec;\n    const EC_GROUP *group;\n\n    GetEC(self, ec);\n    group = EC_KEY_get0_group(ec);\n    if (!group)\n        return Qnil;\n\n    return ec_group_new(group);\n}\n\n/*\n * call-seq:\n *   key.group = group\n *\n * Sets the EC::Group for the key. The group structure is internally copied so\n * modification to _group_ after assigning to a key has no effect on the key.\n */\nstatic VALUE\nossl_ec_key_set_group(VALUE self, VALUE group_v)\n{\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n    rb_raise(ePKeyError, \"pkeys are immutable on OpenSSL 3.0\");\n#else\n    EC_KEY *ec;\n    EC_GROUP *group;\n\n    GetEC(self, ec);\n    GetECGroup(group_v, group);\n\n    if (EC_KEY_set_group(ec, group) != 1)\n        ossl_raise(ePKeyError, \"EC_KEY_set_group\");\n\n    return group_v;\n#endif\n}\n\n/*\n *  call-seq:\n *     key.private_key   => OpenSSL::BN\n *\n *  See the OpenSSL documentation for EC_KEY_get0_private_key()\n */\nstatic VALUE ossl_ec_key_get_private_key(VALUE self)\n{\n    OSSL_3_const EC_KEY *ec;\n    const BIGNUM *bn;\n\n    GetEC(self, ec);\n    if ((bn = EC_KEY_get0_private_key(ec)) == NULL)\n        return Qnil;\n\n    return ossl_bn_new(bn);\n}\n\n/*\n *  call-seq:\n *     key.private_key = openssl_bn\n *\n *  See the OpenSSL documentation for EC_KEY_set_private_key()\n */\nstatic VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)\n{\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n    rb_raise(ePKeyError, \"pkeys are immutable on OpenSSL 3.0\");\n#else\n    EC_KEY *ec;\n    BIGNUM *bn = NULL;\n\n    GetEC(self, ec);\n    if (!NIL_P(private_key))\n        bn = GetBNPtr(private_key);\n\n    switch (EC_KEY_set_private_key(ec, bn)) {\n      case 1:\n        break;\n      case 0:\n        if (bn == NULL)\n            break;\n        /* fallthrough */\n      default:\n        ossl_raise(ePKeyError, \"EC_KEY_set_private_key\");\n    }\n\n    return private_key;\n#endif\n}\n\n/*\n *  call-seq:\n *     key.public_key   => OpenSSL::PKey::EC::Point\n *\n *  See the OpenSSL documentation for EC_KEY_get0_public_key()\n */\nstatic VALUE ossl_ec_key_get_public_key(VALUE self)\n{\n    OSSL_3_const EC_KEY *ec;\n    const EC_POINT *point;\n\n    GetEC(self, ec);\n    if ((point = EC_KEY_get0_public_key(ec)) == NULL)\n        return Qnil;\n\n    return ec_point_new(point, EC_KEY_get0_group(ec));\n}\n\n/*\n *  call-seq:\n *     key.public_key = ec_point\n *\n *  See the OpenSSL documentation for EC_KEY_set_public_key()\n */\nstatic VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)\n{\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n    rb_raise(ePKeyError, \"pkeys are immutable on OpenSSL 3.0\");\n#else\n    EC_KEY *ec;\n    EC_POINT *point = NULL;\n\n    GetEC(self, ec);\n    if (!NIL_P(public_key))\n        GetECPoint(public_key, point);\n\n    switch (EC_KEY_set_public_key(ec, point)) {\n      case 1:\n        break;\n      case 0:\n        if (point == NULL)\n            break;\n        /* fallthrough */\n      default:\n        ossl_raise(ePKeyError, \"EC_KEY_set_public_key\");\n    }\n\n    return public_key;\n#endif\n}\n\n/*\n *  call-seq:\n *     key.public? => true or false\n *\n *  Returns whether this EC instance has a public key. The public key\n *  (EC::Point) can be retrieved with EC#public_key.\n */\nstatic VALUE ossl_ec_key_is_public(VALUE self)\n{\n    OSSL_3_const EC_KEY *ec;\n\n    GetEC(self, ec);\n\n    return EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse;\n}\n\n/*\n *  call-seq:\n *     key.private? => true or false\n *\n *  Returns whether this EC instance has a private key. The private key (BN) can\n *  be retrieved with EC#private_key.\n */\nstatic VALUE ossl_ec_key_is_private(VALUE self)\n{\n    OSSL_3_const EC_KEY *ec;\n\n    GetEC(self, ec);\n\n    return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse;\n}\n\n/*\n *  call-seq:\n *     key.export([cipher, password]) => String\n *     key.to_pem([cipher, password]) => String\n *\n * Serializes a private or public key to a PEM-encoding.\n *\n * [When the key contains public components only]\n *\n *   Serializes it into an X.509 SubjectPublicKeyInfo.\n *   The parameters _cipher_ and _password_ are ignored.\n *\n *   A PEM-encoded key will look like:\n *\n *     -----BEGIN PUBLIC KEY-----\n *     [...]\n *     -----END PUBLIC KEY-----\n *\n *   Consider using #public_to_pem instead. This serializes the key into an\n *   X.509 SubjectPublicKeyInfo regardless of whether it is a public key\n *   or a private key.\n *\n * [When the key contains private components, and no parameters are given]\n *\n *   Serializes it into a SEC 1/RFC 5915 ECPrivateKey.\n *\n *   A PEM-encoded key will look like:\n *\n *     -----BEGIN EC PRIVATE KEY-----\n *     [...]\n *     -----END EC PRIVATE KEY-----\n *\n * [When the key contains private components, and _cipher_ and _password_ are given]\n *\n *   Serializes it into a SEC 1/RFC 5915 ECPrivateKey\n *   and encrypts it in OpenSSL's traditional PEM encryption format.\n *   _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an\n *   instance of OpenSSL::Cipher.\n *\n *   An encrypted PEM-encoded key will look like:\n *\n *     -----BEGIN EC PRIVATE KEY-----\n *     Proc-Type: 4,ENCRYPTED\n *     DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0\n *\n *     [...]\n *     -----END EC PRIVATE KEY-----\n *\n *   Note that this format uses MD5 to derive the encryption key, and hence\n *   will not be available on FIPS-compliant systems.\n *\n * <b>This method is kept for compatibility.</b>\n * This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is\n * required.\n *\n * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem\n * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.\n */\nstatic VALUE\nossl_ec_key_export(int argc, VALUE *argv, VALUE self)\n{\n    OSSL_3_const EC_KEY *ec;\n\n    GetEC(self, ec);\n    if (EC_KEY_get0_public_key(ec) == NULL)\n        ossl_raise(ePKeyError, \"can't export - no public key set\");\n    if (EC_KEY_get0_private_key(ec))\n        return ossl_pkey_export_traditional(argc, argv, self, 0);\n    else\n        return ossl_pkey_export_spki(self, 0);\n}\n\n/*\n *  call-seq:\n *     key.to_der   => String\n *\n * Serializes a private or public key to a DER-encoding.\n *\n * See #to_pem for details.\n *\n * <b>This method is kept for compatibility.</b>\n * This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is\n * required.\n *\n * Consider using #public_to_der or #private_to_der instead.\n */\nstatic VALUE\nossl_ec_key_to_der(VALUE self)\n{\n    OSSL_3_const EC_KEY *ec;\n\n    GetEC(self, ec);\n    if (EC_KEY_get0_public_key(ec) == NULL)\n        ossl_raise(ePKeyError, \"can't export - no public key set\");\n    if (EC_KEY_get0_private_key(ec))\n        return ossl_pkey_export_traditional(0, NULL, self, 1);\n    else\n        return ossl_pkey_export_spki(self, 1);\n}\n/*\n *  call-seq:\n *     key.generate_key!   => self\n *\n * Generates a new random private and public key.\n *\n * See also the OpenSSL documentation for EC_KEY_generate_key()\n *\n * === Example\n *   ec = OpenSSL::PKey::EC.new(\"prime256v1\")\n *   p ec.private_key # => nil\n *   ec.generate_key!\n *   p ec.private_key # => #<OpenSSL::BN XXXXXX>\n */\nstatic VALUE ossl_ec_key_generate_key(VALUE self)\n{\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n    rb_raise(ePKeyError, \"pkeys are immutable on OpenSSL 3.0\");\n#else\n    EC_KEY *ec;\n\n    GetEC(self, ec);\n    if (EC_KEY_generate_key(ec) != 1)\n        ossl_raise(ePKeyError, \"EC_KEY_generate_key\");\n\n    return self;\n#endif\n}\n\n/*\n * call-seq:\n *    key.check_key   => true\n *\n * Raises an exception if the key is invalid.\n *\n * See also the man page EVP_PKEY_public_check(3).\n */\nstatic VALUE ossl_ec_key_check_key(VALUE self)\n{\n#ifdef HAVE_EVP_PKEY_CHECK\n    EVP_PKEY *pkey;\n    EVP_PKEY_CTX *pctx;\n    const EC_KEY *ec;\n\n    GetPKey(self, pkey);\n    GetEC(self, ec);\n    pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);\n    if (!pctx)\n        ossl_raise(ePKeyError, \"EVP_PKEY_CTX_new\");\n\n    if (EC_KEY_get0_private_key(ec) != NULL) {\n        if (EVP_PKEY_check(pctx) != 1) {\n            EVP_PKEY_CTX_free(pctx);\n            ossl_raise(ePKeyError, \"EVP_PKEY_check\");\n        }\n    }\n    else {\n        if (EVP_PKEY_public_check(pctx) != 1) {\n            EVP_PKEY_CTX_free(pctx);\n            ossl_raise(ePKeyError, \"EVP_PKEY_public_check\");\n        }\n    }\n\n    EVP_PKEY_CTX_free(pctx);\n#else\n    EC_KEY *ec;\n\n    GetEC(self, ec);\n    if (EC_KEY_check_key(ec) != 1)\n        ossl_raise(ePKeyError, \"EC_KEY_check_key\");\n#endif\n\n    return Qtrue;\n}\n\n/*\n * OpenSSL::PKey::EC::Group\n */\nstatic void\nossl_ec_group_free(void *ptr)\n{\n    EC_GROUP_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ec_group_type = {\n    \"OpenSSL/ec_group\",\n    {\n        0, ossl_ec_group_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_ec_group_alloc(VALUE klass)\n{\n    return TypedData_Wrap_Struct(klass, &ossl_ec_group_type, NULL);\n}\n\nstatic VALUE\nec_group_new(const EC_GROUP *group)\n{\n    VALUE obj;\n    EC_GROUP *group_new;\n\n    obj = ossl_ec_group_alloc(cEC_GROUP);\n    group_new = EC_GROUP_dup(group);\n    if (!group_new)\n        ossl_raise(eEC_GROUP, \"EC_GROUP_dup\");\n    RTYPEDDATA_DATA(obj) = group_new;\n\n    return obj;\n}\n\n/*\n * call-seq:\n *   OpenSSL::PKey::EC::Group.new(ec_group)\n *   OpenSSL::PKey::EC::Group.new(pem_or_der_encoded)\n *   OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b)\n *   OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b)\n *\n * Creates a new EC::Group object.\n *\n * If the first argument is :GFp or :GF2m, creates a new curve with given\n * parameters.\n */\nstatic VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)\n{\n    VALUE arg1, arg2, arg3, arg4;\n    EC_GROUP *group;\n\n    TypedData_Get_Struct(self, EC_GROUP, &ossl_ec_group_type, group);\n    if (group)\n        ossl_raise(rb_eRuntimeError, \"EC_GROUP is already initialized\");\n\n    switch (rb_scan_args(argc, argv, \"13\", &arg1, &arg2, &arg3, &arg4)) {\n      case 1:\n        if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {\n            const EC_GROUP *arg1_group;\n\n            GetECGroup(arg1, arg1_group);\n            if ((group = EC_GROUP_dup(arg1_group)) == NULL)\n                ossl_raise(eEC_GROUP, \"EC_GROUP_dup\");\n        } else {\n            BIO *in = ossl_obj2bio(&arg1);\n\n            group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);\n            if (!group) {\n                OSSL_BIO_reset(in);\n                group = d2i_ECPKParameters_bio(in, NULL);\n            }\n\n            BIO_free(in);\n\n            if (!group) {\n                const char *name = StringValueCStr(arg1);\n                int nid = OBJ_sn2nid(name);\n\n                ossl_clear_error(); /* ignore errors in d2i_ECPKParameters_bio() */\n                if (nid == NID_undef)\n                    ossl_raise(eEC_GROUP, \"unknown curve name (%\"PRIsVALUE\")\", arg1);\n#if !defined(OPENSSL_IS_AWSLC)\n                group = EC_GROUP_new_by_curve_name(nid);\n#else /* EC_GROUPs are static and immutable by default in AWS-LC. */\n                group = EC_GROUP_new_by_curve_name_mutable(nid);\n#endif\n                if (group == NULL)\n                    ossl_raise(eEC_GROUP, \"unable to create curve (%\"PRIsVALUE\")\", arg1);\n\n                EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);\n                EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);\n            }\n        }\n\n        break;\n      case 4:\n        if (SYMBOL_P(arg1)) {\n            EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;\n            const BIGNUM *p = GetBNPtr(arg2);\n            const BIGNUM *a = GetBNPtr(arg3);\n            const BIGNUM *b = GetBNPtr(arg4);\n\n            if (arg1 == sym_GFp) {\n                new_curve = EC_GROUP_new_curve_GFp;\n            }\n#if !defined(OPENSSL_NO_EC2M)\n            else if (arg1 == sym_GF2m) {\n                new_curve = EC_GROUP_new_curve_GF2m;\n            }\n#endif\n            else {\n                ossl_raise(rb_eArgError, \"unknown symbol, must be :GFp or :GF2m\");\n            }\n\n            if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)\n                ossl_raise(eEC_GROUP, \"EC_GROUP_new_by_GF*\");\n        } else {\n            ossl_raise(rb_eArgError, \"unknown argument, must be :GFp or :GF2m\");\n        }\n\n        break;\n      default:\n        ossl_raise(rb_eArgError, \"wrong number of arguments (given %d, expected 1 or 4)\", argc);\n    }\n\n    ASSUME(group);\n    RTYPEDDATA_DATA(self) = group;\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_ec_group_initialize_copy(VALUE self, VALUE other)\n{\n    EC_GROUP *group, *group_new;\n\n    TypedData_Get_Struct(self, EC_GROUP, &ossl_ec_group_type, group_new);\n    if (group_new)\n        ossl_raise(eEC_GROUP, \"EC::Group already initialized\");\n    GetECGroup(other, group);\n\n    group_new = EC_GROUP_dup(group);\n    if (!group_new)\n        ossl_raise(eEC_GROUP, \"EC_GROUP_dup\");\n    RTYPEDDATA_DATA(self) = group_new;\n\n    return self;\n}\n\n/*\n * call-seq:\n *   group1.eql?(group2)   => true | false\n *   group1 == group2   => true | false\n *\n * Returns +true+ if the two groups use the same curve and have the same\n * parameters, +false+ otherwise.\n */\nstatic VALUE ossl_ec_group_eql(VALUE a, VALUE b)\n{\n    EC_GROUP *group1 = NULL, *group2 = NULL;\n\n    GetECGroup(a, group1);\n    GetECGroup(b, group2);\n\n    switch (EC_GROUP_cmp(group1, group2, ossl_bn_ctx)) {\n      case 0: return Qtrue;\n      case 1: return Qfalse;\n      default: ossl_raise(eEC_GROUP, \"EC_GROUP_cmp\");\n    }\n}\n\n/*\n * call-seq:\n *   group.generator   => ec_point\n *\n * Returns the generator of the group.\n *\n * See the OpenSSL documentation for EC_GROUP_get0_generator()\n */\nstatic VALUE ossl_ec_group_get_generator(VALUE self)\n{\n    EC_GROUP *group;\n    const EC_POINT *generator;\n\n    GetECGroup(self, group);\n    generator = EC_GROUP_get0_generator(group);\n    if (!generator)\n        return Qnil;\n\n    return ec_point_new(generator, group);\n}\n\n/*\n * call-seq:\n *   group.set_generator(generator, order, cofactor)   => self\n *\n * Sets the curve parameters. _generator_ must be an instance of EC::Point that\n * is on the curve. _order_ and _cofactor_ are integers.\n *\n * See the OpenSSL documentation for EC_GROUP_set_generator()\n */\nstatic VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)\n{\n    EC_GROUP *group = NULL;\n    const EC_POINT *point;\n    const BIGNUM *o, *co;\n\n    GetECGroup(self, group);\n    GetECPoint(generator, point);\n    o = GetBNPtr(order);\n    co = GetBNPtr(cofactor);\n\n    if (EC_GROUP_set_generator(group, point, o, co) != 1)\n        ossl_raise(eEC_GROUP, \"EC_GROUP_set_generator\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *   group.get_order   => order_bn\n *\n * Returns the order of the group.\n *\n * See the OpenSSL documentation for EC_GROUP_get_order()\n */\nstatic VALUE ossl_ec_group_get_order(VALUE self)\n{\n    VALUE bn_obj;\n    BIGNUM *bn;\n    EC_GROUP *group;\n\n    GetECGroup(self, group);\n    bn_obj = ossl_bn_new(BN_value_one());\n    bn = GetBNPtr(bn_obj);\n\n    if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)\n        ossl_raise(eEC_GROUP, \"EC_GROUP_get_order\");\n\n    return bn_obj;\n}\n\n/*\n * call-seq:\n *   group.get_cofactor   => cofactor_bn\n *\n * Returns the cofactor of the group.\n *\n * See the OpenSSL documentation for EC_GROUP_get_cofactor()\n */\nstatic VALUE ossl_ec_group_get_cofactor(VALUE self)\n{\n    VALUE bn_obj;\n    BIGNUM *bn;\n    EC_GROUP *group;\n\n    GetECGroup(self, group);\n    bn_obj = ossl_bn_new(BN_value_one());\n    bn = GetBNPtr(bn_obj);\n\n    if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)\n        ossl_raise(eEC_GROUP, \"EC_GROUP_get_cofactor\");\n\n    return bn_obj;\n}\n\n/*\n * call-seq:\n *    group.curve_name -> string or nil\n *\n * Returns the curve name (short name) corresponding to this group, or +nil+\n * if \\OpenSSL does not have an OID associated with the group.\n *\n * See the OpenSSL documentation for EC_GROUP_get_curve_name()\n */\nstatic VALUE ossl_ec_group_get_curve_name(VALUE self)\n{\n    EC_GROUP *group;\n    int nid;\n\n    GetECGroup(self, group);\n    nid = EC_GROUP_get_curve_name(group);\n    if (nid == NID_undef)\n        return Qnil;\n    return rb_str_new_cstr(OBJ_nid2sn(nid));\n}\n\n/*\n * call-seq:\n *   EC.builtin_curves => [[sn, comment], ...]\n *\n * Obtains a list of all predefined curves by the OpenSSL. Curve names are\n * returned as sn.\n *\n * See the OpenSSL documentation for EC_get_builtin_curves().\n */\nstatic VALUE ossl_s_builtin_curves(VALUE self)\n{\n    EC_builtin_curve *curves = NULL;\n    int n;\n    int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));\n    VALUE ary, ret;\n\n    curves = ALLOCA_N(EC_builtin_curve, crv_len);\n    if (curves == NULL)\n        return Qnil;\n    if (!EC_get_builtin_curves(curves, crv_len))\n        ossl_raise(rb_eRuntimeError, \"EC_get_builtin_curves\");\n\n    ret = rb_ary_new2(crv_len);\n\n    for (n = 0; n < crv_len; n++) {\n        const char *sname = OBJ_nid2sn(curves[n].nid);\n        const char *comment = curves[n].comment;\n\n        ary = rb_ary_new2(2);\n        rb_ary_push(ary, rb_str_new2(sname));\n        rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);\n        rb_ary_push(ret, ary);\n    }\n\n    return ret;\n}\n\n/*\n * call-seq:\n *   group.asn1_flag -> Integer\n *\n * Returns the flags set on the group.\n *\n * See also #asn1_flag=.\n */\nstatic VALUE ossl_ec_group_get_asn1_flag(VALUE self)\n{\n    EC_GROUP *group = NULL;\n    int flag;\n\n    GetECGroup(self, group);\n    flag = EC_GROUP_get_asn1_flag(group);\n\n    return INT2NUM(flag);\n}\n\n/*\n * call-seq:\n *   group.asn1_flag = flags\n *\n * Sets flags on the group. The flag value is used to determine how to encode\n * the group: encode explicit parameters or named curve using an OID.\n *\n * The flag value can be either of:\n *\n * * EC::NAMED_CURVE\n * * EC::EXPLICIT_CURVE\n *\n * See the OpenSSL documentation for EC_GROUP_set_asn1_flag().\n */\nstatic VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)\n{\n    EC_GROUP *group = NULL;\n\n    GetECGroup(self, group);\n    EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));\n\n    return flag_v;\n}\n\n/*\n * call-seq:\n *   group.point_conversion_form -> Symbol\n *\n * Returns the form how EC::Point data is encoded as ASN.1.\n *\n * See also #point_conversion_form=.\n */\nstatic VALUE ossl_ec_group_get_point_conversion_form(VALUE self)\n{\n    EC_GROUP *group;\n    point_conversion_form_t form;\n\n    GetECGroup(self, group);\n    form = EC_GROUP_get_point_conversion_form(group);\n\n    switch (form) {\n      case POINT_CONVERSION_UNCOMPRESSED:\n        return sym_uncompressed;\n      case POINT_CONVERSION_COMPRESSED:\n        return sym_compressed;\n      case POINT_CONVERSION_HYBRID:\n        return sym_hybrid;\n      default:\n        ossl_raise(eEC_GROUP, \"unsupported point conversion form: %d, \" \\\n                   \"this module should be updated\", form);\n    }\n}\n\nstatic point_conversion_form_t\nparse_point_conversion_form_symbol(VALUE sym)\n{\n    if (sym == sym_uncompressed)\n        return POINT_CONVERSION_UNCOMPRESSED;\n    if (sym == sym_compressed)\n        return POINT_CONVERSION_COMPRESSED;\n    if (sym == sym_hybrid)\n        return POINT_CONVERSION_HYBRID;\n    ossl_raise(rb_eArgError, \"unsupported point conversion form %+\"PRIsVALUE\n               \" (expected :compressed, :uncompressed, or :hybrid)\", sym);\n}\n\n/*\n * call-seq:\n *   group.point_conversion_form = form\n *\n * Sets the form how EC::Point data is encoded as ASN.1 as defined in X9.62.\n *\n * _format_ can be one of these:\n *\n * +:compressed+::\n *   Encoded as z||x, where z is an octet indicating which solution of the\n *   equation y is. z will be 0x02 or 0x03.\n * +:uncompressed+::\n *   Encoded as z||x||y, where z is an octet 0x04.\n * +:hybrid+::\n *   Encodes as z||x||y, where z is an octet indicating which solution of the\n *   equation y is. z will be 0x06 or 0x07.\n *\n * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()\n */\nstatic VALUE\nossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)\n{\n    EC_GROUP *group;\n    point_conversion_form_t form;\n\n    GetECGroup(self, group);\n    form = parse_point_conversion_form_symbol(form_v);\n\n    EC_GROUP_set_point_conversion_form(group, form);\n\n    return form_v;\n}\n\n/*\n * call-seq:\n *   group.seed   => String or nil\n *\n * See the OpenSSL documentation for EC_GROUP_get0_seed()\n */\nstatic VALUE ossl_ec_group_get_seed(VALUE self)\n{\n    EC_GROUP *group = NULL;\n    size_t seed_len;\n\n    GetECGroup(self, group);\n    seed_len = EC_GROUP_get_seed_len(group);\n\n    if (seed_len == 0)\n        return Qnil;\n\n    return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);\n}\n\n/*\n * call-seq:\n *   group.seed = seed  => seed\n *\n * See the OpenSSL documentation for EC_GROUP_set_seed()\n */\nstatic VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)\n{\n    EC_GROUP *group = NULL;\n\n    GetECGroup(self, group);\n    StringValue(seed);\n\n    if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))\n        ossl_raise(eEC_GROUP, \"EC_GROUP_set_seed\");\n\n    return seed;\n}\n\n/* get/set curve GFp, GF2m */\n\n/*\n * call-seq:\n *   group.degree   => integer\n *\n * See the OpenSSL documentation for EC_GROUP_get_degree()\n */\nstatic VALUE ossl_ec_group_get_degree(VALUE self)\n{\n    EC_GROUP *group = NULL;\n\n    GetECGroup(self, group);\n\n    return INT2NUM(EC_GROUP_get_degree(group));\n}\n\nstatic VALUE ossl_ec_group_to_string(VALUE self, int format)\n{\n    EC_GROUP *group;\n    BIO *out;\n    int i = -1;\n    VALUE str;\n\n    GetECGroup(self, group);\n\n    if (!(out = BIO_new(BIO_s_mem())))\n        ossl_raise(eEC_GROUP, \"BIO_new(BIO_s_mem())\");\n\n    switch(format) {\n      case EXPORT_PEM:\n        i = PEM_write_bio_ECPKParameters(out, group);\n        break;\n      case EXPORT_DER:\n        i = i2d_ECPKParameters_bio(out, group);\n        break;\n      default:\n        BIO_free(out);\n        ossl_raise(rb_eRuntimeError, \"unknown format (internal error)\");\n    }\n\n    if (i != 1) {\n        BIO_free(out);\n        ossl_raise(ePKeyError, NULL);\n    }\n\n    str = ossl_membio2str(out);\n\n    return str;\n}\n\n/*\n * call-seq:\n *   group.to_pem   => String\n *\n *  See the OpenSSL documentation for PEM_write_bio_ECPKParameters()\n */\nstatic VALUE ossl_ec_group_to_pem(VALUE self)\n{\n    return ossl_ec_group_to_string(self, EXPORT_PEM);\n}\n\n/*\n * call-seq:\n *   group.to_der   => String\n *\n * See the OpenSSL documentation for i2d_ECPKParameters_bio()\n */\nstatic VALUE ossl_ec_group_to_der(VALUE self)\n{\n    return ossl_ec_group_to_string(self, EXPORT_DER);\n}\n\n/*\n * call-seq:\n *   group.to_text   => String\n *\n * See the OpenSSL documentation for ECPKParameters_print()\n */\nstatic VALUE ossl_ec_group_to_text(VALUE self)\n{\n    EC_GROUP *group;\n    BIO *out;\n    VALUE str;\n\n    GetECGroup(self, group);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eEC_GROUP, \"BIO_new(BIO_s_mem())\");\n    }\n    if (!ECPKParameters_print(out, group, 0)) {\n        BIO_free(out);\n        ossl_raise(eEC_GROUP, NULL);\n    }\n    str = ossl_membio2str(out);\n\n    return str;\n}\n\n\n/*\n * OpenSSL::PKey::EC::Point\n */\nstatic void\nossl_ec_point_free(void *ptr)\n{\n    EC_POINT_clear_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ec_point_type = {\n    \"OpenSSL/EC_POINT\",\n    {\n        0, ossl_ec_point_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_ec_point_alloc(VALUE klass)\n{\n    return TypedData_Wrap_Struct(klass, &ossl_ec_point_type, NULL);\n}\n\nstatic VALUE\nec_point_new(const EC_POINT *point, const EC_GROUP *group)\n{\n    EC_POINT *point_new;\n    VALUE obj;\n\n    obj = ossl_ec_point_alloc(cEC_POINT);\n    point_new = EC_POINT_dup(point, group);\n    if (!point_new)\n        ossl_raise(eEC_POINT, \"EC_POINT_dup\");\n    RTYPEDDATA_DATA(obj) = point_new;\n    rb_ivar_set(obj, id_i_group, ec_group_new(group));\n\n    return obj;\n}\n\nstatic VALUE ossl_ec_point_initialize_copy(VALUE, VALUE);\n/*\n * call-seq:\n *   OpenSSL::PKey::EC::Point.new(point)\n *   OpenSSL::PKey::EC::Point.new(group [, encoded_point])\n *\n * Creates a new instance of OpenSSL::PKey::EC::Point. If the only argument is\n * an instance of EC::Point, a copy is returned. Otherwise, creates a point\n * that belongs to _group_.\n *\n * _encoded_point_ is the octet string representation of the point. This\n * must be either a String or an OpenSSL::BN.\n */\nstatic VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)\n{\n    EC_POINT *point;\n    VALUE group_v, arg2;\n    const EC_GROUP *group;\n\n    TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point);\n    if (point)\n        rb_raise(eEC_POINT, \"EC_POINT already initialized\");\n\n    rb_scan_args(argc, argv, \"11\", &group_v, &arg2);\n    if (rb_obj_is_kind_of(group_v, cEC_POINT)) {\n        if (argc != 1)\n            rb_raise(rb_eArgError, \"invalid second argument\");\n        return ossl_ec_point_initialize_copy(self, group_v);\n    }\n\n    GetECGroup(group_v, group);\n    if (argc == 1) {\n        point = EC_POINT_new(group);\n        if (!point)\n            ossl_raise(eEC_POINT, \"EC_POINT_new\");\n    }\n    else {\n        if (rb_obj_is_kind_of(arg2, cBN)) {\n            point = EC_POINT_bn2point(group, GetBNPtr(arg2), NULL, ossl_bn_ctx);\n            if (!point)\n                ossl_raise(eEC_POINT, \"EC_POINT_bn2point\");\n        }\n        else {\n            StringValue(arg2);\n            point = EC_POINT_new(group);\n            if (!point)\n                ossl_raise(eEC_POINT, \"EC_POINT_new\");\n            if (!EC_POINT_oct2point(group, point,\n                                    (unsigned char *)RSTRING_PTR(arg2),\n                                    RSTRING_LEN(arg2), ossl_bn_ctx)) {\n                EC_POINT_free(point);\n                ossl_raise(eEC_POINT, \"EC_POINT_oct2point\");\n            }\n        }\n    }\n\n    RTYPEDDATA_DATA(self) = point;\n    rb_ivar_set(self, id_i_group, group_v);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_ec_point_initialize_copy(VALUE self, VALUE other)\n{\n    EC_POINT *point, *point_new;\n    EC_GROUP *group;\n    VALUE group_v;\n\n    TypedData_Get_Struct(self, EC_POINT, &ossl_ec_point_type, point_new);\n    if (point_new)\n        ossl_raise(eEC_POINT, \"EC::Point already initialized\");\n    GetECPoint(other, point);\n\n    group_v = rb_obj_dup(rb_attr_get(other, id_i_group));\n    GetECGroup(group_v, group);\n\n    point_new = EC_POINT_dup(point, group);\n    if (!point_new)\n        ossl_raise(eEC_POINT, \"EC_POINT_dup\");\n    RTYPEDDATA_DATA(self) = point_new;\n    rb_ivar_set(self, id_i_group, group_v);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   point1.eql?(point2) => true | false\n *   point1 == point2 => true | false\n */\nstatic VALUE ossl_ec_point_eql(VALUE a, VALUE b)\n{\n    EC_POINT *point1, *point2;\n    VALUE group_v1 = rb_attr_get(a, id_i_group);\n    VALUE group_v2 = rb_attr_get(b, id_i_group);\n    const EC_GROUP *group;\n\n    if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)\n        return Qfalse;\n\n    GetECPoint(a, point1);\n    GetECPoint(b, point2);\n    GetECGroup(group_v1, group);\n\n    switch (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx)) {\n      case 0: return Qtrue;\n      case 1: return Qfalse;\n      default: ossl_raise(eEC_POINT, \"EC_POINT_cmp\");\n    }\n\n    UNREACHABLE;\n}\n\n/*\n * call-seq:\n *   point.infinity? => true | false\n */\nstatic VALUE ossl_ec_point_is_at_infinity(VALUE self)\n{\n    EC_POINT *point;\n    const EC_GROUP *group;\n\n    GetECPoint(self, point);\n    GetECPointGroup(self, group);\n\n    switch (EC_POINT_is_at_infinity(group, point)) {\n      case 1: return Qtrue;\n      case 0: return Qfalse;\n      default: ossl_raise(eEC_POINT, \"EC_POINT_is_at_infinity\");\n    }\n\n    UNREACHABLE;\n}\n\n/*\n * call-seq:\n *   point.on_curve? => true | false\n */\nstatic VALUE ossl_ec_point_is_on_curve(VALUE self)\n{\n    EC_POINT *point;\n    const EC_GROUP *group;\n\n    GetECPoint(self, point);\n    GetECPointGroup(self, group);\n\n    switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {\n      case 1: return Qtrue;\n      case 0: return Qfalse;\n      default: ossl_raise(eEC_POINT, \"EC_POINT_is_on_curve\");\n    }\n\n    UNREACHABLE;\n}\n\n/*\n * call-seq:\n *   point.make_affine! => self\n *\n * This method is deprecated and should not be used. This is a no-op.\n */\nstatic VALUE ossl_ec_point_make_affine(VALUE self)\n{\n    EC_POINT *point;\n    const EC_GROUP *group;\n\n    GetECPoint(self, point);\n    GetECPointGroup(self, group);\n\n    rb_warn(\"OpenSSL::PKey::EC::Point#make_affine! is deprecated\");\n#if !defined(OSSL_HAVE_IMMUTABLE_PKEY) && !defined(OPENSSL_IS_AWSLC)\n    if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)\n        ossl_raise(eEC_POINT, \"EC_POINT_make_affine\");\n#endif\n\n    return self;\n}\n\n/*\n * call-seq:\n *   point.invert! => self\n */\nstatic VALUE ossl_ec_point_invert(VALUE self)\n{\n    EC_POINT *point;\n    const EC_GROUP *group;\n\n    GetECPoint(self, point);\n    GetECPointGroup(self, group);\n\n    if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)\n        ossl_raise(eEC_POINT, \"EC_POINT_invert\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *   point.set_to_infinity! => self\n */\nstatic VALUE ossl_ec_point_set_to_infinity(VALUE self)\n{\n    EC_POINT *point;\n    const EC_GROUP *group;\n\n    GetECPoint(self, point);\n    GetECPointGroup(self, group);\n\n    if (EC_POINT_set_to_infinity(group, point) != 1)\n        ossl_raise(eEC_POINT, \"EC_POINT_set_to_infinity\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *    point.to_octet_string(conversion_form) -> String\n *\n * Returns the octet string representation of the elliptic curve point.\n *\n * _conversion_form_ specifies how the point is converted. Possible values are:\n *\n * - +:compressed+\n * - +:uncompressed+\n * - +:hybrid+\n */\nstatic VALUE\nossl_ec_point_to_octet_string(VALUE self, VALUE conversion_form)\n{\n    EC_POINT *point;\n    const EC_GROUP *group;\n    point_conversion_form_t form;\n    VALUE str;\n    size_t len;\n\n    GetECPoint(self, point);\n    GetECPointGroup(self, group);\n    form = parse_point_conversion_form_symbol(conversion_form);\n\n    len = EC_POINT_point2oct(group, point, form, NULL, 0, ossl_bn_ctx);\n    if (!len)\n        ossl_raise(eEC_POINT, \"EC_POINT_point2oct\");\n    str = rb_str_new(NULL, (long)len);\n    if (!EC_POINT_point2oct(group, point, form,\n                            (unsigned char *)RSTRING_PTR(str), len,\n                            ossl_bn_ctx))\n        ossl_raise(eEC_POINT, \"EC_POINT_point2oct\");\n    return str;\n}\n\n/*\n * call-seq:\n *   point.add(point) => point\n *\n * Performs elliptic curve point addition.\n */\nstatic VALUE ossl_ec_point_add(VALUE self, VALUE other)\n{\n    EC_POINT *point_self, *point_other, *point_result;\n    const EC_GROUP *group;\n    VALUE group_v = rb_attr_get(self, id_i_group);\n    VALUE result;\n\n    GetECPoint(self, point_self);\n    GetECPoint(other, point_other);\n    GetECGroup(group_v, group);\n\n    result = rb_obj_alloc(cEC_POINT);\n    ossl_ec_point_initialize(1, &group_v, result);\n    GetECPoint(result, point_result);\n\n    if (EC_POINT_add(group, point_result, point_self, point_other, ossl_bn_ctx) != 1) {\n        ossl_raise(eEC_POINT, \"EC_POINT_add\");\n    }\n\n    return result;\n}\n\n/*\n * call-seq:\n *   point.mul(bn1 [, bn2]) => point\n *\n * Performs elliptic curve point multiplication.\n *\n * The first form calculates <tt>bn1 * point + bn2 * G</tt>, where +G+ is the\n * generator of the group of _point_. _bn2_ may be omitted, and in that case,\n * the result is just <tt>bn1 * point</tt>.\n *\n * Before version 4.0.0, and when compiled with OpenSSL 1.1.1 or older, this\n * method allowed another form:\n *   point.mul(bns, points [, bn2]) => point\n */\nstatic VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self)\n{\n    EC_POINT *point_self, *point_result;\n    const EC_GROUP *group;\n    VALUE group_v = rb_attr_get(self, id_i_group);\n    VALUE arg1, arg2, arg3, result;\n    const BIGNUM *bn_g = NULL;\n\n    GetECPoint(self, point_self);\n    GetECGroup(group_v, group);\n\n    result = rb_obj_alloc(cEC_POINT);\n    ossl_ec_point_initialize(1, &group_v, result);\n    GetECPoint(result, point_result);\n\n    rb_scan_args(argc, argv, \"12\", &arg1, &arg2, &arg3);\n    if (RB_TYPE_P(arg1, T_ARRAY) || argc > 2)\n        rb_raise(rb_eNotImpError, \"OpenSSL::PKey::EC::Point#mul with arrays \" \\\n                 \"is no longer supported\");\n\n    BIGNUM *bn = GetBNPtr(arg1);\n    if (!NIL_P(arg2))\n        bn_g = GetBNPtr(arg2);\n    if (EC_POINT_mul(group, point_result, bn_g, point_self, bn, ossl_bn_ctx) != 1)\n        ossl_raise(eEC_POINT, NULL);\n\n    return result;\n}\n\nvoid Init_ossl_ec(void)\n{\n#undef rb_intern\n    /*\n     * Document-class: OpenSSL::PKey::EC\n     *\n     * OpenSSL::PKey::EC provides access to Elliptic Curve Digital Signature\n     * Algorithm (ECDSA) and Elliptic Curve Diffie-Hellman (ECDH).\n     *\n     * === Key exchange\n     *   ec1 = OpenSSL::PKey::EC.generate(\"prime256v1\")\n     *   ec2 = OpenSSL::PKey::EC.generate(\"prime256v1\")\n     *   # ec1 and ec2 have own private key respectively\n     *   shared_key1 = ec1.dh_compute_key(ec2.public_key)\n     *   shared_key2 = ec2.dh_compute_key(ec1.public_key)\n     *\n     *   p shared_key1 == shared_key2 #=> true\n     */\n    cEC = rb_define_class_under(mPKey, \"EC\", cPKey);\n    cEC_GROUP = rb_define_class_under(cEC, \"Group\", rb_cObject);\n    cEC_POINT = rb_define_class_under(cEC, \"Point\", rb_cObject);\n    eEC_GROUP = rb_define_class_under(cEC_GROUP, \"Error\", eOSSLError);\n    eEC_POINT = rb_define_class_under(cEC_POINT, \"Error\", eOSSLError);\n\n    sym_GFp = ID2SYM(rb_intern_const(\"GFp\"));\n    sym_GF2m = ID2SYM(rb_intern_const(\"GF2m\"));\n\n    sym_uncompressed = ID2SYM(rb_intern_const(\"uncompressed\"));\n    sym_compressed = ID2SYM(rb_intern_const(\"compressed\"));\n    sym_hybrid = ID2SYM(rb_intern_const(\"hybrid\"));\n\n    rb_define_const(cEC, \"NAMED_CURVE\", INT2NUM(OPENSSL_EC_NAMED_CURVE));\n    rb_define_const(cEC, \"EXPLICIT_CURVE\", INT2NUM(OPENSSL_EC_EXPLICIT_CURVE));\n\n    rb_define_singleton_method(cEC, \"builtin_curves\", ossl_s_builtin_curves, 0);\n\n    rb_define_singleton_method(cEC, \"generate\", ossl_ec_key_s_generate, 1);\n    rb_define_method(cEC, \"initialize\", ossl_ec_key_initialize, -1);\n#ifndef HAVE_EVP_PKEY_DUP\n    rb_define_method(cEC, \"initialize_copy\", ossl_ec_key_initialize_copy, 1);\n#endif\n\n    rb_define_method(cEC, \"group\", ossl_ec_key_get_group, 0);\n    rb_define_method(cEC, \"group=\", ossl_ec_key_set_group, 1);\n    rb_define_method(cEC, \"private_key\", ossl_ec_key_get_private_key, 0);\n    rb_define_method(cEC, \"private_key=\", ossl_ec_key_set_private_key, 1);\n    rb_define_method(cEC, \"public_key\", ossl_ec_key_get_public_key, 0);\n    rb_define_method(cEC, \"public_key=\", ossl_ec_key_set_public_key, 1);\n    rb_define_method(cEC, \"private?\", ossl_ec_key_is_private, 0);\n    rb_define_method(cEC, \"public?\", ossl_ec_key_is_public, 0);\n    rb_define_alias(cEC, \"private_key?\", \"private?\");\n    rb_define_alias(cEC, \"public_key?\", \"public?\");\n/*  rb_define_method(cEC, \"\", ossl_ec_key_get_, 0);\n    rb_define_method(cEC, \"=\", ossl_ec_key_set_ 1);\n    set/get enc_flags\n    set/get _conv_from\n    set/get asn1_flag (can use ruby to call self.group.asn1_flag)\n    set/get precompute_mult\n*/\n    rb_define_method(cEC, \"generate_key!\", ossl_ec_key_generate_key, 0);\n    rb_define_alias(cEC, \"generate_key\", \"generate_key!\");\n    rb_define_method(cEC, \"check_key\", ossl_ec_key_check_key, 0);\n\n    rb_define_method(cEC, \"export\", ossl_ec_key_export, -1);\n    rb_define_alias(cEC, \"to_pem\", \"export\");\n    rb_define_method(cEC, \"to_der\", ossl_ec_key_to_der, 0);\n\n\n    rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);\n    rb_define_method(cEC_GROUP, \"initialize\", ossl_ec_group_initialize, -1);\n    rb_define_method(cEC_GROUP, \"initialize_copy\", ossl_ec_group_initialize_copy, 1);\n    rb_define_method(cEC_GROUP, \"eql?\", ossl_ec_group_eql, 1);\n    rb_define_alias(cEC_GROUP, \"==\", \"eql?\");\n/* copy/dup/cmp */\n\n    rb_define_method(cEC_GROUP, \"generator\", ossl_ec_group_get_generator, 0);\n    rb_define_method(cEC_GROUP, \"set_generator\", ossl_ec_group_set_generator, 3);\n    rb_define_method(cEC_GROUP, \"order\", ossl_ec_group_get_order, 0);\n    rb_define_method(cEC_GROUP, \"cofactor\", ossl_ec_group_get_cofactor, 0);\n\n    rb_define_method(cEC_GROUP, \"curve_name\", ossl_ec_group_get_curve_name, 0);\n/*    rb_define_method(cEC_GROUP, \"curve_name=\", ossl_ec_group_set_curve_name, 1); */\n\n    rb_define_method(cEC_GROUP, \"asn1_flag\", ossl_ec_group_get_asn1_flag, 0);\n    rb_define_method(cEC_GROUP, \"asn1_flag=\", ossl_ec_group_set_asn1_flag, 1);\n\n    rb_define_method(cEC_GROUP, \"point_conversion_form\", ossl_ec_group_get_point_conversion_form, 0);\n    rb_define_method(cEC_GROUP, \"point_conversion_form=\", ossl_ec_group_set_point_conversion_form, 1);\n\n    rb_define_method(cEC_GROUP, \"seed\", ossl_ec_group_get_seed, 0);\n    rb_define_method(cEC_GROUP, \"seed=\", ossl_ec_group_set_seed, 1);\n\n/* get/set GFp, GF2m */\n\n    rb_define_method(cEC_GROUP, \"degree\", ossl_ec_group_get_degree, 0);\n\n/* check* */\n\n\n    rb_define_method(cEC_GROUP, \"to_pem\", ossl_ec_group_to_pem, 0);\n    rb_define_method(cEC_GROUP, \"to_der\", ossl_ec_group_to_der, 0);\n    rb_define_method(cEC_GROUP, \"to_text\", ossl_ec_group_to_text, 0);\n\n\n    rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);\n    rb_define_method(cEC_POINT, \"initialize\", ossl_ec_point_initialize, -1);\n    rb_define_method(cEC_POINT, \"initialize_copy\", ossl_ec_point_initialize_copy, 1);\n    rb_attr(cEC_POINT, rb_intern(\"group\"), 1, 0, 0);\n    rb_define_method(cEC_POINT, \"eql?\", ossl_ec_point_eql, 1);\n    rb_define_alias(cEC_POINT, \"==\", \"eql?\");\n\n    rb_define_method(cEC_POINT, \"infinity?\", ossl_ec_point_is_at_infinity, 0);\n    rb_define_method(cEC_POINT, \"on_curve?\", ossl_ec_point_is_on_curve, 0);\n    rb_define_method(cEC_POINT, \"make_affine!\", ossl_ec_point_make_affine, 0);\n    rb_define_method(cEC_POINT, \"invert!\", ossl_ec_point_invert, 0);\n    rb_define_method(cEC_POINT, \"set_to_infinity!\", ossl_ec_point_set_to_infinity, 0);\n/* all the other methods */\n\n    rb_define_method(cEC_POINT, \"to_octet_string\", ossl_ec_point_to_octet_string, 1);\n    rb_define_method(cEC_POINT, \"add\", ossl_ec_point_add, 1);\n    rb_define_method(cEC_POINT, \"mul\", ossl_ec_point_mul, -1);\n\n    id_i_group = rb_intern(\"@group\");\n}\n\n#else /* defined NO_EC */\nvoid Init_ossl_ec(void)\n{\n}\n#endif /* NO_EC */\n"
  },
  {
    "path": "ext/openssl/ossl_pkey_rsa.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#if !defined(OPENSSL_NO_RSA)\n\n#define GetPKeyRSA(obj, pkey) do { \\\n    GetPKey((obj), (pkey)); \\\n    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { /* PARANOIA? */ \\\n        ossl_raise(rb_eRuntimeError, \"THIS IS NOT A RSA!\") ; \\\n    } \\\n} while (0)\n#define GetRSA(obj, rsa) do { \\\n    EVP_PKEY *_pkey; \\\n    GetPKeyRSA((obj), _pkey); \\\n    (rsa) = EVP_PKEY_get0_RSA(_pkey); \\\n    if ((rsa) == NULL) \\\n        ossl_raise(ePKeyError, \"failed to get RSA from EVP_PKEY\"); \\\n} while (0)\n\nstatic inline int\nRSA_HAS_PRIVATE(OSSL_3_const RSA *rsa)\n{\n    const BIGNUM *e, *d;\n\n    RSA_get0_key(rsa, NULL, &e, &d);\n    return e && d;\n}\n\nstatic inline int\nRSA_PRIVATE(VALUE obj, OSSL_3_const RSA *rsa)\n{\n    return RSA_HAS_PRIVATE(rsa) || OSSL_PKEY_IS_PRIVATE(obj);\n}\n\n/*\n * Classes\n */\nVALUE cRSA;\n\n/*\n * Private\n */\n/*\n * call-seq:\n *   RSA.new -> rsa\n *   RSA.new(encoded_key [, password ]) -> rsa\n *   RSA.new(encoded_key) { password } -> rsa\n *   RSA.new(size [, exponent]) -> rsa\n *\n * Generates or loads an \\RSA keypair.\n *\n * If called without arguments, creates a new instance with no key components\n * set. They can be set individually by #set_key, #set_factors, and\n * #set_crt_params.\n * This form is not compatible with OpenSSL 3.0 or later.\n *\n * If called with a String, tries to parse as DER or PEM encoding of an \\RSA key.\n * Note that if _password_ is not specified, but the key is encrypted with a\n * password, \\OpenSSL will prompt for it.\n * See also OpenSSL::PKey.read which can parse keys of any kind.\n *\n * If called with a number, generates a new key pair. This form works as an\n * alias of RSA.generate.\n *\n * Examples:\n *   OpenSSL::PKey::RSA.new 2048\n *   OpenSSL::PKey::RSA.new File.read 'rsa.pem'\n *   OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my password'\n */\nstatic VALUE\nossl_rsa_initialize(int argc, VALUE *argv, VALUE self)\n{\n    EVP_PKEY *pkey;\n    RSA *rsa;\n    BIO *in = NULL;\n    VALUE arg, pass;\n    int type;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n\n    /* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */\n    rb_scan_args(argc, argv, \"02\", &arg, &pass);\n    if (argc == 0) {\n#ifdef OSSL_HAVE_IMMUTABLE_PKEY\n        rb_raise(rb_eArgError, \"OpenSSL::PKey::RSA.new cannot be called \" \\\n                 \"without arguments; pkeys are immutable with OpenSSL 3.0\");\n#else\n        rsa = RSA_new();\n        if (!rsa)\n            ossl_raise(ePKeyError, \"RSA_new\");\n        goto legacy;\n#endif\n    }\n\n    pass = ossl_pem_passwd_value(pass);\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n\n    /* First try RSAPublicKey format */\n    rsa = d2i_RSAPublicKey_bio(in, NULL);\n    if (rsa)\n        goto legacy;\n    OSSL_BIO_reset(in);\n    rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);\n    if (rsa)\n        goto legacy;\n    OSSL_BIO_reset(in);\n\n    /* Use the generic routine */\n    pkey = ossl_pkey_read_generic(in, pass);\n    BIO_free(in);\n    if (!pkey)\n        ossl_raise(ePKeyError, \"Neither PUB key nor PRIV key\");\n\n    type = EVP_PKEY_base_id(pkey);\n    if (type != EVP_PKEY_RSA) {\n        EVP_PKEY_free(pkey);\n        rb_raise(ePKeyError, \"incorrect pkey type: %s\", OBJ_nid2sn(type));\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n\n  legacy:\n    BIO_free(in);\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) {\n        EVP_PKEY_free(pkey);\n        RSA_free(rsa);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_RSA\");\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n    return self;\n}\n\n#ifndef HAVE_EVP_PKEY_DUP\n/* :nodoc: */\nstatic VALUE\nossl_rsa_initialize_copy(VALUE self, VALUE other)\n{\n    EVP_PKEY *pkey;\n    RSA *rsa, *rsa_new;\n\n    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);\n    if (pkey)\n        rb_raise(rb_eTypeError, \"pkey already initialized\");\n    GetRSA(other, rsa);\n\n    rsa_new = (RSA *)ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey,\n                              (d2i_of_void *)d2i_RSAPrivateKey,\n                              (char *)rsa);\n    if (!rsa_new)\n        ossl_raise(ePKeyError, \"ASN1_dup\");\n\n    pkey = EVP_PKEY_new();\n    if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) {\n        RSA_free(rsa_new);\n        ossl_raise(ePKeyError, \"EVP_PKEY_assign_RSA\");\n    }\n    RTYPEDDATA_DATA(self) = pkey;\n\n    return self;\n}\n#endif\n\n/*\n * call-seq:\n *   rsa.public? => true\n *\n * The return value is always +true+ since every private key is also a public\n * key.\n */\nstatic VALUE\nossl_rsa_is_public(VALUE self)\n{\n    OSSL_3_const RSA *rsa;\n\n    GetRSA(self, rsa);\n    /*\n     * This method should check for n and e.  BUG.\n     */\n    (void)rsa;\n    return Qtrue;\n}\n\n/*\n * call-seq:\n *   rsa.private? => true | false\n *\n * Does this keypair contain a private key?\n */\nstatic VALUE\nossl_rsa_is_private(VALUE self)\n{\n    OSSL_3_const RSA *rsa;\n\n    GetRSA(self, rsa);\n\n    return RSA_PRIVATE(self, rsa) ? Qtrue : Qfalse;\n}\n\nstatic int\ncan_export_rsaprivatekey(VALUE self)\n{\n    OSSL_3_const RSA *rsa;\n    const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;\n\n    GetRSA(self, rsa);\n\n    RSA_get0_key(rsa, &n, &e, &d);\n    RSA_get0_factors(rsa, &p, &q);\n    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);\n\n    return n && e && d && p && q && dmp1 && dmq1 && iqmp;\n}\n\n/*\n * call-seq:\n *   rsa.export([cipher, password]) => PEM-format String\n *   rsa.to_pem([cipher, password]) => PEM-format String\n *   rsa.to_s([cipher, password]) => PEM-format String\n *\n * Serializes a private or public key to a PEM-encoding.\n *\n * [When the key contains public components only]\n *\n *   Serializes it into an X.509 SubjectPublicKeyInfo.\n *   The parameters _cipher_ and _password_ are ignored.\n *\n *   A PEM-encoded key will look like:\n *\n *     -----BEGIN PUBLIC KEY-----\n *     [...]\n *     -----END PUBLIC KEY-----\n *\n *   Consider using #public_to_pem instead. This serializes the key into an\n *   X.509 SubjectPublicKeyInfo regardless of whether the key is a public key\n *   or a private key.\n *\n * [When the key contains private components, and no parameters are given]\n *\n *   Serializes it into a PKCS #1 RSAPrivateKey.\n *\n *   A PEM-encoded key will look like:\n *\n *     -----BEGIN RSA PRIVATE KEY-----\n *     [...]\n *     -----END RSA PRIVATE KEY-----\n *\n * [When the key contains private components, and _cipher_ and _password_ are given]\n *\n *   Serializes it into a PKCS #1 RSAPrivateKey\n *   and encrypts it in OpenSSL's traditional PEM encryption format.\n *   _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an\n *   instance of OpenSSL::Cipher.\n *\n *   An encrypted PEM-encoded key will look like:\n *\n *     -----BEGIN RSA PRIVATE KEY-----\n *     Proc-Type: 4,ENCRYPTED\n *     DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0\n *\n *     [...]\n *     -----END RSA PRIVATE KEY-----\n *\n *   Note that this format uses MD5 to derive the encryption key, and hence\n *   will not be available on FIPS-compliant systems.\n *\n * <b>This method is kept for compatibility.</b>\n * This should only be used when the PKCS #1 RSAPrivateKey format is required.\n *\n * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem\n * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.\n */\nstatic VALUE\nossl_rsa_export(int argc, VALUE *argv, VALUE self)\n{\n    if (can_export_rsaprivatekey(self))\n        return ossl_pkey_export_traditional(argc, argv, self, 0);\n    else\n        return ossl_pkey_export_spki(self, 0);\n}\n\n/*\n * call-seq:\n *   rsa.to_der => DER-format String\n *\n * Serializes a private or public key to a DER-encoding.\n *\n * See #to_pem for details.\n *\n * <b>This method is kept for compatibility.</b>\n * This should only be used when the PKCS #1 RSAPrivateKey format is required.\n *\n * Consider using #public_to_der or #private_to_der instead.\n */\nstatic VALUE\nossl_rsa_to_der(VALUE self)\n{\n    if (can_export_rsaprivatekey(self))\n        return ossl_pkey_export_traditional(0, NULL, self, 1);\n    else\n        return ossl_pkey_export_spki(self, 1);\n}\n\n/*\n * call-seq:\n *    rsa.sign_pss(digest, data, salt_length:, mgf1_hash:) -> String\n *\n * Signs _data_ using the Probabilistic Signature Scheme (RSA-PSS) and returns\n * the calculated signature.\n *\n * PKeyError will be raised if an error occurs.\n *\n * See #verify_pss for the verification operation.\n *\n * === Parameters\n * _digest_::\n *   A String containing the message digest algorithm name.\n * _data_::\n *   A String. The data to be signed.\n * _salt_length_::\n *   The length in octets of the salt. Two special values are reserved:\n *   +:digest+ means the digest length, and +:max+ means the maximum possible\n *   length for the combination of the private key and the selected message\n *   digest algorithm.\n * _mgf1_hash_::\n *   The hash algorithm used in MGF1 (the currently supported mask generation\n *   function (MGF)).\n *\n * === Example\n *   data = \"Sign me!\"\n *   pkey = OpenSSL::PKey::RSA.new(2048)\n *   signature = pkey.sign_pss(\"SHA256\", data, salt_length: :max, mgf1_hash: \"SHA256\")\n *   pub_key = OpenSSL::PKey.read(pkey.public_to_der)\n *   puts pub_key.verify_pss(\"SHA256\", signature, data,\n *                           salt_length: :auto, mgf1_hash: \"SHA256\") # => true\n */\nstatic VALUE\nossl_rsa_sign_pss(int argc, VALUE *argv, VALUE self)\n{\n    VALUE digest, data, options, kwargs[2], signature, mgf1md_holder, md_holder;\n    static ID kwargs_ids[2];\n    EVP_PKEY *pkey;\n    EVP_PKEY_CTX *pkey_ctx;\n    const EVP_MD *md, *mgf1md;\n    EVP_MD_CTX *md_ctx;\n    size_t buf_len;\n    int salt_len;\n\n    if (!kwargs_ids[0]) {\n        kwargs_ids[0] = rb_intern_const(\"salt_length\");\n        kwargs_ids[1] = rb_intern_const(\"mgf1_hash\");\n    }\n    rb_scan_args(argc, argv, \"2:\", &digest, &data, &options);\n    rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);\n    if (kwargs[0] == ID2SYM(rb_intern(\"max\")))\n        salt_len = -2; /* RSA_PSS_SALTLEN_MAX_SIGN */\n    else if (kwargs[0] == ID2SYM(rb_intern(\"digest\")))\n        salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */\n    else\n        salt_len = NUM2INT(kwargs[0]);\n    mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder);\n\n    pkey = GetPrivPKeyPtr(self);\n    buf_len = EVP_PKEY_size(pkey);\n    md = ossl_evp_md_fetch(digest, &md_holder);\n    StringValue(data);\n    signature = rb_str_new(NULL, (long)buf_len);\n\n    md_ctx = EVP_MD_CTX_new();\n    if (!md_ctx)\n        goto err;\n\n    if (EVP_DigestSignInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)\n        goto err;\n\n    if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)\n        goto err;\n\n    if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)\n        goto err;\n\n    if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)\n        goto err;\n\n    if (EVP_DigestSignUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)\n        goto err;\n\n    if (EVP_DigestSignFinal(md_ctx, (unsigned char *)RSTRING_PTR(signature), &buf_len) != 1)\n        goto err;\n\n    rb_str_set_len(signature, (long)buf_len);\n\n    EVP_MD_CTX_free(md_ctx);\n    return signature;\n\n  err:\n    EVP_MD_CTX_free(md_ctx);\n    ossl_raise(ePKeyError, NULL);\n}\n\n/*\n * call-seq:\n *    rsa.verify_pss(digest, signature, data, salt_length:, mgf1_hash:) -> true | false\n *\n * Verifies _data_ using the Probabilistic Signature Scheme (RSA-PSS).\n *\n * The return value is +true+ if the signature is valid, +false+ otherwise.\n * PKeyError will be raised if an error occurs.\n *\n * See #sign_pss for the signing operation and an example code.\n *\n * === Parameters\n * _digest_::\n *   A String containing the message digest algorithm name.\n * _data_::\n *   A String. The data to be signed.\n * _salt_length_::\n *   The length in octets of the salt. Two special values are reserved:\n *   +:digest+ means the digest length, and +:auto+ means automatically\n *   determining the length based on the signature.\n * _mgf1_hash_::\n *   The hash algorithm used in MGF1.\n */\nstatic VALUE\nossl_rsa_verify_pss(int argc, VALUE *argv, VALUE self)\n{\n    VALUE digest, signature, data, options, kwargs[2], mgf1md_holder, md_holder;\n    static ID kwargs_ids[2];\n    EVP_PKEY *pkey;\n    EVP_PKEY_CTX *pkey_ctx;\n    const EVP_MD *md, *mgf1md;\n    EVP_MD_CTX *md_ctx;\n    int result, salt_len;\n\n    if (!kwargs_ids[0]) {\n        kwargs_ids[0] = rb_intern_const(\"salt_length\");\n        kwargs_ids[1] = rb_intern_const(\"mgf1_hash\");\n    }\n    rb_scan_args(argc, argv, \"3:\", &digest, &signature, &data, &options);\n    rb_get_kwargs(options, kwargs_ids, 2, 0, kwargs);\n    if (kwargs[0] == ID2SYM(rb_intern(\"auto\")))\n        salt_len = -2; /* RSA_PSS_SALTLEN_AUTO */\n    else if (kwargs[0] == ID2SYM(rb_intern(\"digest\")))\n        salt_len = -1; /* RSA_PSS_SALTLEN_DIGEST */\n    else\n        salt_len = NUM2INT(kwargs[0]);\n    mgf1md = ossl_evp_md_fetch(kwargs[1], &mgf1md_holder);\n\n    GetPKey(self, pkey);\n    md = ossl_evp_md_fetch(digest, &md_holder);\n    StringValue(signature);\n    StringValue(data);\n\n    md_ctx = EVP_MD_CTX_new();\n    if (!md_ctx)\n        goto err;\n\n    if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, md, NULL, pkey) != 1)\n        goto err;\n\n    if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1)\n        goto err;\n\n    if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, salt_len) != 1)\n        goto err;\n\n    if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1md) != 1)\n        goto err;\n\n    if (EVP_DigestVerifyUpdate(md_ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)\n        goto err;\n\n    result = EVP_DigestVerifyFinal(md_ctx,\n                                   (unsigned char *)RSTRING_PTR(signature),\n                                   RSTRING_LEN(signature));\n    EVP_MD_CTX_free(md_ctx);\n\n    switch (result) {\n      case 0:\n        ossl_clear_error();\n        return Qfalse;\n      case 1:\n        return Qtrue;\n      default:\n        ossl_raise(ePKeyError, \"EVP_DigestVerifyFinal\");\n    }\n\n  err:\n    EVP_MD_CTX_free(md_ctx);\n    ossl_raise(ePKeyError, NULL);\n}\n\n/*\n * Document-method: OpenSSL::PKey::RSA#set_key\n * call-seq:\n *   rsa.set_key(n, e, d) -> self\n *\n * Sets _n_, _e_, _d_ for the RSA instance.\n */\nOSSL_PKEY_BN_DEF3(rsa, RSA, key, n, e, d)\n/*\n * Document-method: OpenSSL::PKey::RSA#set_factors\n * call-seq:\n *   rsa.set_factors(p, q) -> self\n *\n * Sets _p_, _q_ for the RSA instance.\n */\nOSSL_PKEY_BN_DEF2(rsa, RSA, factors, p, q)\n/*\n * Document-method: OpenSSL::PKey::RSA#set_crt_params\n * call-seq:\n *   rsa.set_crt_params(dmp1, dmq1, iqmp) -> self\n *\n * Sets _dmp1_, _dmq1_, _iqmp_ for the RSA instance. They are calculated by\n * <tt>d mod (p - 1)</tt>, <tt>d mod (q - 1)</tt> and <tt>q^(-1) mod p</tt>\n * respectively.\n */\nOSSL_PKEY_BN_DEF3(rsa, RSA, crt_params, dmp1, dmq1, iqmp)\n\n/*\n * INIT\n */\n#define DefRSAConst(x) rb_define_const(cRSA, #x, INT2NUM(RSA_##x))\n\nvoid\nInit_ossl_rsa(void)\n{\n    /* Document-class: OpenSSL::PKey::RSA\n     *\n     * RSA is an asymmetric public key algorithm that has been formalized in\n     * RFC 3447. It is in widespread use in public key infrastructures (PKI)\n     * where certificates (cf. OpenSSL::X509::Certificate) often are issued\n     * on the basis of a public/private RSA key pair. RSA is used in a wide\n     * field of applications such as secure (symmetric) key exchange, e.g.\n     * when establishing a secure TLS/SSL connection. It is also used in\n     * various digital signature schemes.\n     */\n    cRSA = rb_define_class_under(mPKey, \"RSA\", cPKey);\n\n    rb_define_method(cRSA, \"initialize\", ossl_rsa_initialize, -1);\n#ifndef HAVE_EVP_PKEY_DUP\n    rb_define_method(cRSA, \"initialize_copy\", ossl_rsa_initialize_copy, 1);\n#endif\n\n    rb_define_method(cRSA, \"public?\", ossl_rsa_is_public, 0);\n    rb_define_method(cRSA, \"private?\", ossl_rsa_is_private, 0);\n    rb_define_method(cRSA, \"export\", ossl_rsa_export, -1);\n    rb_define_alias(cRSA, \"to_pem\", \"export\");\n    rb_define_alias(cRSA, \"to_s\", \"export\");\n    rb_define_method(cRSA, \"to_der\", ossl_rsa_to_der, 0);\n    rb_define_method(cRSA, \"sign_pss\", ossl_rsa_sign_pss, -1);\n    rb_define_method(cRSA, \"verify_pss\", ossl_rsa_verify_pss, -1);\n\n    DEF_OSSL_PKEY_BN(cRSA, rsa, n);\n    DEF_OSSL_PKEY_BN(cRSA, rsa, e);\n    DEF_OSSL_PKEY_BN(cRSA, rsa, d);\n    DEF_OSSL_PKEY_BN(cRSA, rsa, p);\n    DEF_OSSL_PKEY_BN(cRSA, rsa, q);\n    DEF_OSSL_PKEY_BN(cRSA, rsa, dmp1);\n    DEF_OSSL_PKEY_BN(cRSA, rsa, dmq1);\n    DEF_OSSL_PKEY_BN(cRSA, rsa, iqmp);\n    rb_define_method(cRSA, \"set_key\", ossl_rsa_set_key, 3);\n    rb_define_method(cRSA, \"set_factors\", ossl_rsa_set_factors, 2);\n    rb_define_method(cRSA, \"set_crt_params\", ossl_rsa_set_crt_params, 3);\n\n/*\n * TODO: Test it\n    rb_define_method(cRSA, \"blinding_on!\", ossl_rsa_blinding_on, 0);\n    rb_define_method(cRSA, \"blinding_off!\", ossl_rsa_blinding_off, 0);\n */\n}\n\n#else /* defined NO_RSA */\nvoid\nInit_ossl_rsa(void)\n{\n}\n#endif /* NO_RSA */\n"
  },
  {
    "path": "ext/openssl/ossl_provider.c",
    "content": "/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#ifdef OSSL_USE_PROVIDER\n#define NewProvider(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_provider_type, 0)\n#define SetProvider(obj, provider) do { \\\n    if (!(provider)) { \\\n        ossl_raise(rb_eRuntimeError, \"Provider wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (provider); \\\n} while(0)\n#define GetProvider(obj, provider) do { \\\n    TypedData_Get_Struct((obj), OSSL_PROVIDER, &ossl_provider_type, (provider)); \\\n    if (!(provider)) { \\\n        ossl_raise(rb_eRuntimeError, \"PROVIDER wasn't initialized.\"); \\\n    } \\\n} while (0)\n\nstatic const rb_data_type_t ossl_provider_type = {\n    \"OpenSSL/Provider\",\n    {\n        0,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Classes\n */\n/* Document-class: OpenSSL::Provider\n *\n * This class is the access to openssl's Provider\n * See also, https://www.openssl.org/docs/manmaster/man7/provider.html\n */\nstatic VALUE cProvider;\n/* Document-class: OpenSSL::Provider::ProviderError\n *\n * This is the generic exception for OpenSSL::Provider related errors\n */\nstatic VALUE eProviderError;\n\n/*\n * call-seq:\n *    OpenSSL::Provider.load(name) -> provider\n *\n * This method loads and initializes a provider\n */\nstatic VALUE\nossl_provider_s_load(VALUE klass, VALUE name)\n{\n    OSSL_PROVIDER *provider = NULL;\n    VALUE obj;\n\n    const char *provider_name_ptr = StringValueCStr(name);\n\n    provider = OSSL_PROVIDER_load(NULL, provider_name_ptr);\n    if (provider == NULL) {\n        ossl_raise(eProviderError, \"Failed to load %s provider\", provider_name_ptr);\n    }\n    obj = NewProvider(klass);\n    SetProvider(obj, provider);\n\n    return obj;\n}\n\nstruct ary_with_state { VALUE ary; int state; };\nstruct rb_push_provider_name_args { OSSL_PROVIDER *prov; VALUE ary; };\n\nstatic VALUE\nrb_push_provider_name(VALUE rb_push_provider_name_args)\n{\n    struct rb_push_provider_name_args *args = (struct rb_push_provider_name_args *)rb_push_provider_name_args;\n\n    VALUE name = rb_str_new2(OSSL_PROVIDER_get0_name(args->prov));\n    return rb_ary_push(args->ary, name);\n}\n\nstatic int\npush_provider(OSSL_PROVIDER *prov, void *cbdata)\n{\n    struct ary_with_state *ary_with_state = (struct ary_with_state *)cbdata;\n    struct rb_push_provider_name_args args = { prov, ary_with_state->ary };\n\n    rb_protect(rb_push_provider_name, (VALUE)&args, &ary_with_state->state);\n    if (ary_with_state->state) {\n        return 0;\n    } else {\n        return 1;\n    }\n}\n\n/*\n * call-seq:\n *    OpenSSL::Provider.provider_names -> [provider_name, ...]\n *\n * Returns an array of currently loaded provider names.\n */\nstatic VALUE\nossl_provider_s_provider_names(VALUE klass)\n{\n    VALUE ary = rb_ary_new();\n    struct ary_with_state cbdata = { ary, 0 };\n\n    int result = OSSL_PROVIDER_do_all(NULL, &push_provider, (void*)&cbdata);\n    if (result != 1 ) {\n        if (cbdata.state) {\n            rb_jump_tag(cbdata.state);\n        } else {\n            ossl_raise(eProviderError, \"Failed to load provider names\");\n        }\n    }\n\n    return ary;\n}\n\n/*\n * call-seq:\n *    provider.unload -> true\n *\n * This method unloads this provider.\n *\n * if provider unload fails or already unloaded, it raises OpenSSL::Provider::ProviderError\n */\nstatic VALUE\nossl_provider_unload(VALUE self)\n{\n    OSSL_PROVIDER *prov;\n    if (RTYPEDDATA_DATA(self) == NULL) {\n        ossl_raise(eProviderError, \"Provider already unloaded.\");\n    }\n    GetProvider(self, prov);\n\n    int result = OSSL_PROVIDER_unload(prov);\n\n    if (result != 1) {\n        ossl_raise(eProviderError, \"Failed to unload provider\");\n    }\n    RTYPEDDATA_DATA(self) = NULL;\n    return Qtrue;\n}\n\n/*\n * call-seq:\n *    provider.name -> string\n *\n * Get the name of this provider.\n *\n * if this provider is already unloaded, it raises OpenSSL::Provider::ProviderError\n */\nstatic VALUE\nossl_provider_get_name(VALUE self)\n{\n    OSSL_PROVIDER *prov;\n    if (RTYPEDDATA_DATA(self) == NULL) {\n        ossl_raise(eProviderError, \"Provider already unloaded.\");\n    }\n    GetProvider(self, prov);\n\n    return rb_str_new2(OSSL_PROVIDER_get0_name(prov));\n}\n\n/*\n * call-seq:\n *    provider.inspect -> string\n *\n * Pretty prints this provider.\n */\nstatic VALUE\nossl_provider_inspect(VALUE self)\n{\n    OSSL_PROVIDER *prov;\n    if (RTYPEDDATA_DATA(self) == NULL ) {\n        return rb_sprintf(\"#<%\"PRIsVALUE\" unloaded provider>\", rb_obj_class(self));\n    }\n    GetProvider(self, prov);\n\n    return rb_sprintf(\"#<%\"PRIsVALUE\" name=\\\"%s\\\">\",\n                      rb_obj_class(self), OSSL_PROVIDER_get0_name(prov));\n}\n\nvoid\nInit_ossl_provider(void)\n{\n    cProvider = rb_define_class_under(mOSSL, \"Provider\", rb_cObject);\n    eProviderError = rb_define_class_under(cProvider, \"ProviderError\", eOSSLError);\n\n    rb_undef_alloc_func(cProvider);\n    rb_define_singleton_method(cProvider, \"load\", ossl_provider_s_load, 1);\n    rb_define_singleton_method(cProvider, \"provider_names\", ossl_provider_s_provider_names, 0);\n\n    rb_define_method(cProvider, \"unload\", ossl_provider_unload, 0);\n    rb_define_method(cProvider, \"name\", ossl_provider_get_name, 0);\n    rb_define_method(cProvider, \"inspect\", ossl_provider_inspect, 0);\n}\n#else\nvoid\nInit_ossl_provider(void)\n{\n}\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_provider.h",
    "content": "#if !defined(OSSL_PROVIDER_H)\n#define OSSL_PROVIDER_H\n\nvoid Init_ossl_provider(void);\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_rand.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n *\n * All rights reserved.\n *\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\nstatic VALUE mRandom;\nstatic VALUE eRandomError;\n\n/*\n *  call-seq:\n *     seed(str) -> str\n *\n * ::seed is equivalent to ::add where _entropy_ is length of _str_.\n */\nstatic VALUE\nossl_rand_seed(VALUE self, VALUE str)\n{\n    StringValue(str);\n    RAND_seed(RSTRING_PTR(str), RSTRING_LENINT(str));\n\n    return str;\n}\n\n/*\n *  call-seq:\n *     add(str, entropy) -> self\n *\n * Mixes the bytes from _str_ into the Pseudo Random Number Generator(PRNG)\n * state.\n *\n * Thus, if the data from _str_ are unpredictable to an adversary, this\n * increases the uncertainty about the state and makes the PRNG output less\n * predictable.\n *\n * The _entropy_ argument is (the lower bound of) an estimate of how much\n * randomness is contained in _str_, measured in bytes.\n *\n * === Example\n *\n *    pid = $$\n *    now = Time.now\n *    ary = [now.to_i, now.nsec, 1000, pid]\n *    OpenSSL::Random.add(ary.join, 0.0)\n *    OpenSSL::Random.seed(ary.join)\n */\nstatic VALUE\nossl_rand_add(VALUE self, VALUE str, VALUE entropy)\n{\n    StringValue(str);\n    RAND_add(RSTRING_PTR(str), RSTRING_LENINT(str), NUM2DBL(entropy));\n\n    return self;\n}\n\n/*\n *  call-seq:\n *     load_random_file(filename) -> true\n *\n * Reads bytes from _filename_ and adds them to the PRNG.\n */\nstatic VALUE\nossl_rand_load_file(VALUE self, VALUE filename)\n{\n    if(!RAND_load_file(StringValueCStr(filename), -1)) {\n        ossl_raise(eRandomError, NULL);\n    }\n    return Qtrue;\n}\n\n/*\n *  call-seq:\n *     write_random_file(filename) -> true\n *\n * Writes a number of random generated bytes (currently 1024) to _filename_\n * which can be used to initialize the PRNG by calling ::load_random_file in a\n * later session.\n */\nstatic VALUE\nossl_rand_write_file(VALUE self, VALUE filename)\n{\n    if (RAND_write_file(StringValueCStr(filename)) == -1) {\n        ossl_raise(eRandomError, NULL);\n    }\n    return Qtrue;\n}\n\n/*\n *  call-seq:\n *      random_bytes(length) -> string\n *\n * Generates a String with _length_ number of cryptographically strong\n * pseudo-random bytes.\n *\n * === Example\n *\n *    OpenSSL::Random.random_bytes(12)\n *    #=> \"...\"\n */\nstatic VALUE\nossl_rand_bytes(VALUE self, VALUE len)\n{\n    VALUE str;\n    int n = NUM2INT(len);\n    int ret;\n\n    str = rb_str_new(0, n);\n    ret = RAND_bytes((unsigned char *)RSTRING_PTR(str), n);\n    if (ret == 0) {\n        ossl_raise(eRandomError, \"RAND_bytes\");\n    } else if (ret == -1) {\n        ossl_raise(eRandomError, \"RAND_bytes is not supported\");\n    }\n\n    return str;\n}\n\n#ifdef HAVE_RAND_EGD\n/*\n *  call-seq:\n *     egd(filename) -> true\n *\n * Same as ::egd_bytes but queries 255 bytes by default.\n */\nstatic VALUE\nossl_rand_egd(VALUE self, VALUE filename)\n{\n    if (RAND_egd(StringValueCStr(filename)) == -1) {\n        ossl_raise(eRandomError, NULL);\n    }\n    return Qtrue;\n}\n\n/*\n *  call-seq:\n *     egd_bytes(filename, length) -> true\n *\n * Queries the entropy gathering daemon EGD on socket path given by _filename_.\n *\n * Fetches _length_ number of bytes and uses ::add to seed the OpenSSL built-in\n * PRNG.\n */\nstatic VALUE\nossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)\n{\n    int n = NUM2INT(len);\n\n    if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) {\n        ossl_raise(eRandomError, NULL);\n    }\n    return Qtrue;\n}\n#endif /* HAVE_RAND_EGD */\n\n/*\n *  call-seq:\n *     status? => true | false\n *\n * Return +true+ if the PRNG has been seeded with enough data, +false+ otherwise.\n */\nstatic VALUE\nossl_rand_status(VALUE self)\n{\n    return RAND_status() ? Qtrue : Qfalse;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_rand(void)\n{\n    mRandom = rb_define_module_under(mOSSL, \"Random\");\n\n    eRandomError = rb_define_class_under(mRandom, \"RandomError\", eOSSLError);\n\n    rb_define_module_function(mRandom, \"seed\", ossl_rand_seed, 1);\n    rb_define_module_function(mRandom, \"random_add\", ossl_rand_add, 2);\n    rb_define_module_function(mRandom, \"load_random_file\", ossl_rand_load_file, 1);\n    rb_define_module_function(mRandom, \"write_random_file\", ossl_rand_write_file, 1);\n    rb_define_module_function(mRandom, \"random_bytes\", ossl_rand_bytes, 1);\n    rb_define_alias(rb_singleton_class(mRandom), \"pseudo_bytes\", \"random_bytes\");\n#ifdef HAVE_RAND_EGD\n    rb_define_module_function(mRandom, \"egd\", ossl_rand_egd, 1);\n    rb_define_module_function(mRandom, \"egd_bytes\", ossl_rand_egd_bytes, 2);\n#endif /* HAVE_RAND_EGD */\n    rb_define_module_function(mRandom, \"status?\", ossl_rand_status, 0);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_rand.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_RAND_H_)\n#define _OSSL_RAND_H_\n\nvoid Init_ossl_rand(void);\n\n#endif /* _OSSL_RAND_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_ssl.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2000-2002  GOTOU Yuuzou <gotoyuzo@notwork.org>\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * Copyright (C) 2001-2007  Technorama Ltd. <oss-ruby@technorama.net>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#ifndef OPENSSL_NO_SOCK\n#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))\n\n#if !defined(OPENSSL_NO_NEXTPROTONEG) && !OSSL_IS_LIBRESSL\n# define OSSL_USE_NEXTPROTONEG\n#endif\n\n#ifdef _WIN32\n#  define TO_SOCKET(s) _get_osfhandle(s)\n#else\n#  define TO_SOCKET(s) (s)\n#endif\n\n#define GetSSLCTX(obj, ctx) do { \\\n    TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \\\n} while (0)\n\nVALUE mSSL;\nstatic VALUE eSSLError;\nstatic VALUE cSSLContext;\nVALUE cSSLSocket;\n\nstatic VALUE eSSLErrorWaitReadable;\nstatic VALUE eSSLErrorWaitWritable;\n\nstatic ID id_call, ID_callback_state, id_npn_protocols_encoded, id_each;\nstatic VALUE sym_exception, sym_wait_readable, sym_wait_writable;\n\nstatic ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode,\n          id_i_verify_depth, id_i_verify_callback, id_i_client_ca,\n          id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert,\n          id_i_client_cert_cb, id_i_timeout,\n          id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,\n          id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,\n          id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,\n          id_i_verify_hostname, id_i_keylog_cb, id_i_tmp_dh_callback;\nstatic ID id_i_io, id_i_context, id_i_hostname, id_i_sync_close;\n\nstatic int ossl_ssl_ex_ptr_idx;\nstatic int ossl_sslctx_ex_ptr_idx;\n\nstatic void\nossl_sslctx_mark(void *ptr)\n{\n    SSL_CTX *ctx = ptr;\n    rb_gc_mark((VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx));\n}\n\nstatic void\nossl_sslctx_free(void *ptr)\n{\n    SSL_CTX_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_sslctx_type = {\n    \"OpenSSL/SSL/CTX\",\n    {\n        ossl_sslctx_mark, ossl_sslctx_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_sslctx_s_alloc(VALUE klass)\n{\n    SSL_CTX *ctx;\n    long mode = 0 |\n        SSL_MODE_ENABLE_PARTIAL_WRITE |\n        SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |\n        SSL_MODE_RELEASE_BUFFERS;\n    VALUE obj;\n\n    obj = TypedData_Wrap_Struct(klass, &ossl_sslctx_type, 0);\n    ctx = SSL_CTX_new(TLS_method());\n    if (!ctx) {\n        ossl_raise(eSSLError, \"SSL_CTX_new\");\n    }\n    SSL_CTX_set_mode(ctx, mode);\n    SSL_CTX_set_dh_auto(ctx, 1);\n    RTYPEDDATA_DATA(obj) = ctx;\n    if (!SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj))\n        ossl_raise(eSSLError, \"SSL_CTX_set_ex_data\");\n\n    return obj;\n}\n\nstatic VALUE\nossl_call_client_cert_cb(VALUE obj)\n{\n    VALUE ctx_obj, cb, ary, cert, key;\n\n    ctx_obj = rb_attr_get(obj, id_i_context);\n    cb = rb_attr_get(ctx_obj, id_i_client_cert_cb);\n    if (NIL_P(cb))\n        return Qnil;\n\n    ary = rb_funcallv(cb, id_call, 1, &obj);\n    Check_Type(ary, T_ARRAY);\n    GetX509CertPtr(cert = rb_ary_entry(ary, 0));\n    GetPrivPKeyPtr(key = rb_ary_entry(ary, 1));\n\n    return rb_ary_new3(2, cert, key);\n}\n\nstatic int\nossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)\n{\n    VALUE obj, ret;\n\n    obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    ret = rb_protect(ossl_call_client_cert_cb, obj, NULL);\n    if (NIL_P(ret))\n        return 0;\n\n    *x509 = DupX509CertPtr(RARRAY_AREF(ret, 0));\n    *pkey = DupPKeyPtr(RARRAY_AREF(ret, 1));\n\n    return 1;\n}\n\n#if !defined(OPENSSL_NO_DH)\nstruct tmp_dh_callback_args {\n    VALUE ssl_obj;\n    int is_export;\n    int keylength;\n};\n\nstatic VALUE\nossl_call_tmp_dh_callback(VALUE arg)\n{\n    struct tmp_dh_callback_args *args = (struct tmp_dh_callback_args *)arg;\n    VALUE ctx_obj, cb, obj;\n    const DH *dh;\n\n    ctx_obj = rb_attr_get(args->ssl_obj, id_i_context);\n    cb = rb_attr_get(ctx_obj, id_i_tmp_dh_callback);\n    if (NIL_P(cb))\n        return (VALUE)NULL;\n\n    obj = rb_funcall(cb, id_call, 3, args->ssl_obj, INT2NUM(args->is_export),\n                     INT2NUM(args->keylength));\n    // TODO: We should riase if obj is not DH\n    dh = EVP_PKEY_get0_DH(GetPKeyPtr(obj));\n    if (!dh)\n        ossl_clear_error();\n\n    return (VALUE)dh;\n}\n\nstatic DH *\nossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)\n{\n    int state;\n    VALUE rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    struct tmp_dh_callback_args args = {rb_ssl, is_export, keylength};\n    VALUE ret = rb_protect(ossl_call_tmp_dh_callback, (VALUE)&args, &state);\n    if (state) {\n        rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state));\n        return NULL;\n    }\n    return (DH *)ret;\n}\n#endif /* OPENSSL_NO_DH */\n\nstatic VALUE\ncall_verify_certificate_identity(VALUE ctx_v)\n{\n    X509_STORE_CTX *ctx = (X509_STORE_CTX *)ctx_v;\n    SSL *ssl;\n    VALUE ssl_obj, hostname, cert_obj;\n\n    ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());\n    ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    hostname = rb_attr_get(ssl_obj, id_i_hostname);\n\n    if (!RTEST(hostname)) {\n        rb_warning(\"verify_hostname requires hostname to be set\");\n        return Qtrue;\n    }\n\n    cert_obj = ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));\n    return rb_funcall(mSSL, rb_intern(\"verify_certificate_identity\"), 2,\n                      cert_obj, hostname);\n}\n\nstatic int\nossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)\n{\n    VALUE cb, ssl_obj, sslctx_obj, verify_hostname, ret;\n    SSL *ssl;\n    int status;\n\n    ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());\n    ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    sslctx_obj = rb_attr_get(ssl_obj, id_i_context);\n    cb = rb_attr_get(sslctx_obj, id_i_verify_callback);\n    verify_hostname = rb_attr_get(sslctx_obj, id_i_verify_hostname);\n\n    if (preverify_ok && RTEST(verify_hostname) && !SSL_is_server(ssl) &&\n        !X509_STORE_CTX_get_error_depth(ctx)) {\n        ret = rb_protect(call_verify_certificate_identity, (VALUE)ctx, &status);\n        if (status) {\n            rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));\n            return 0;\n        }\n        if (ret != Qtrue) {\n            preverify_ok = 0;\n            X509_STORE_CTX_set_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH);\n        }\n    }\n\n    return ossl_verify_cb_call(cb, preverify_ok, ctx);\n}\n\nstatic VALUE\nossl_call_session_get_cb(VALUE ary)\n{\n    VALUE ssl_obj, cb;\n\n    Check_Type(ary, T_ARRAY);\n    ssl_obj = rb_ary_entry(ary, 0);\n\n    cb = rb_funcall(ssl_obj, rb_intern(\"session_get_cb\"), 0);\n    if (NIL_P(cb)) return Qnil;\n\n    return rb_funcallv(cb, id_call, 1, &ary);\n}\n\nstatic SSL_SESSION *\nossl_sslctx_session_get_cb(SSL *ssl, const unsigned char *buf, int len, int *copy)\n{\n    VALUE ary, ssl_obj, ret_obj;\n    SSL_SESSION *sess;\n    int state = 0;\n\n    OSSL_Debug(\"SSL SESSION get callback entered\");\n    ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    ary = rb_ary_new2(2);\n    rb_ary_push(ary, ssl_obj);\n    rb_ary_push(ary, rb_str_new((const char *)buf, len));\n\n    ret_obj = rb_protect(ossl_call_session_get_cb, ary, &state);\n    if (state) {\n        rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));\n        return NULL;\n    }\n    if (!rb_obj_is_instance_of(ret_obj, cSSLSession))\n        return NULL;\n\n    GetSSLSession(ret_obj, sess);\n    *copy = 1;\n\n    return sess;\n}\n\nstatic VALUE\nossl_call_session_new_cb(VALUE ary)\n{\n    VALUE ssl_obj, cb;\n\n    Check_Type(ary, T_ARRAY);\n    ssl_obj = rb_ary_entry(ary, 0);\n\n    cb = rb_funcall(ssl_obj, rb_intern(\"session_new_cb\"), 0);\n    if (NIL_P(cb)) return Qnil;\n\n    return rb_funcallv(cb, id_call, 1, &ary);\n}\n\n/* return 1 normal.  return 0 removes the session */\nstatic int\nossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess)\n{\n    VALUE ary, ssl_obj, sess_obj;\n    int state = 0;\n\n    OSSL_Debug(\"SSL SESSION new callback entered\");\n\n    ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    sess_obj = rb_obj_alloc(cSSLSession);\n    SSL_SESSION_up_ref(sess);\n    DATA_PTR(sess_obj) = sess;\n\n    ary = rb_ary_new2(2);\n    rb_ary_push(ary, ssl_obj);\n    rb_ary_push(ary, sess_obj);\n\n    rb_protect(ossl_call_session_new_cb, ary, &state);\n    if (state) {\n        rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));\n    }\n\n    /*\n     * return 0 which means to OpenSSL that the session is still\n     * valid (since we created Ruby Session object) and was not freed by us\n     * with SSL_SESSION_free(). Call SSLContext#remove_session(sess) in\n     * session_get_cb block if you don't want OpenSSL to cache the session\n     * internally.\n     */\n    return 0;\n}\n\n#if !OSSL_IS_LIBRESSL\n/*\n * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements\n * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see\n * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6).\n */\n\nstruct ossl_call_keylog_cb_args {\n    VALUE ssl_obj;\n    const char * line;\n};\n\nstatic VALUE\nossl_call_keylog_cb(VALUE args_v)\n{\n    VALUE sslctx_obj, cb, line_v;\n    struct ossl_call_keylog_cb_args *args = (struct ossl_call_keylog_cb_args *) args_v;\n\n    sslctx_obj = rb_attr_get(args->ssl_obj, id_i_context);\n\n    cb = rb_attr_get(sslctx_obj, id_i_keylog_cb);\n    if (NIL_P(cb)) return Qnil;\n\n    line_v = rb_str_new_cstr(args->line);\n\n    return rb_funcall(cb, id_call, 2, args->ssl_obj, line_v);\n}\n\nstatic void\nossl_sslctx_keylog_cb(const SSL *ssl, const char *line)\n{\n    VALUE ssl_obj;\n    struct ossl_call_keylog_cb_args args;\n    int state = 0;\n\n    OSSL_Debug(\"SSL keylog callback entered\");\n\n    ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    args.ssl_obj = ssl_obj;\n    args.line = line;\n\n    rb_protect(ossl_call_keylog_cb, (VALUE)&args, &state);\n    if (state) {\n        rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));\n    }\n}\n#endif\n\nstatic VALUE\nossl_call_session_remove_cb(VALUE ary)\n{\n    VALUE sslctx_obj, cb;\n\n    Check_Type(ary, T_ARRAY);\n    sslctx_obj = rb_ary_entry(ary, 0);\n\n    cb = rb_attr_get(sslctx_obj, id_i_session_remove_cb);\n    if (NIL_P(cb)) return Qnil;\n\n    return rb_funcallv(cb, id_call, 1, &ary);\n}\n\nstatic void\nossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)\n{\n    VALUE ary, sslctx_obj, sess_obj;\n    int state = 0;\n\n    /*\n     * This callback is also called for all sessions in the internal store\n     * when SSL_CTX_free() is called.\n     */\n    if (rb_during_gc())\n        return;\n\n    OSSL_Debug(\"SSL SESSION remove callback entered\");\n\n    sslctx_obj = (VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx);\n    sess_obj = rb_obj_alloc(cSSLSession);\n    SSL_SESSION_up_ref(sess);\n    DATA_PTR(sess_obj) = sess;\n\n    ary = rb_ary_new2(2);\n    rb_ary_push(ary, sslctx_obj);\n    rb_ary_push(ary, sess_obj);\n\n    rb_protect(ossl_call_session_remove_cb, ary, &state);\n    if (state) {\n/*\n  the SSL_CTX is frozen, nowhere to save state.\n  there is no common accessor method to check it either.\n        rb_ivar_set(sslctx_obj, ID_callback_state, INT2NUM(state));\n*/\n    }\n}\n\nstatic VALUE\nossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))\n{\n    X509 *x509;\n    SSL_CTX *ctx;\n\n    GetSSLCTX(arg, ctx);\n    x509 = DupX509CertPtr(i);\n    if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) {\n        X509_free(x509);\n        ossl_raise(eSSLError, \"SSL_CTX_add_extra_chain_cert\");\n    }\n\n    return i;\n}\n\nstatic VALUE ossl_sslctx_setup(VALUE self);\n\nstatic VALUE\nossl_call_servername_cb(VALUE arg)\n{\n    SSL *ssl = (void *)arg;\n    const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);\n    if (!servername)\n        return Qnil;\n\n    VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    VALUE sslctx_obj = rb_attr_get(ssl_obj, id_i_context);\n    VALUE cb = rb_attr_get(sslctx_obj, id_i_servername_cb);\n    VALUE ary = rb_assoc_new(ssl_obj, rb_str_new_cstr(servername));\n\n    VALUE ret_obj = rb_funcallv(cb, id_call, 1, &ary);\n    if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {\n        SSL_CTX *ctx2;\n        ossl_sslctx_setup(ret_obj);\n        GetSSLCTX(ret_obj, ctx2);\n        if (!SSL_set_SSL_CTX(ssl, ctx2))\n            ossl_raise(eSSLError, \"SSL_set_SSL_CTX\");\n        rb_ivar_set(ssl_obj, id_i_context, ret_obj);\n    } else if (!NIL_P(ret_obj)) {\n        ossl_raise(rb_eArgError, \"servername_cb must return an \"\n                   \"OpenSSL::SSL::SSLContext object or nil\");\n    }\n\n    return Qnil;\n}\n\nstatic int\nssl_servername_cb(SSL *ssl, int *ad, void *arg)\n{\n    int state;\n\n    rb_protect(ossl_call_servername_cb, (VALUE)ssl, &state);\n    if (state) {\n        VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n        rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));\n        return SSL_TLSEXT_ERR_ALERT_FATAL;\n    }\n\n    return SSL_TLSEXT_ERR_OK;\n}\n\nstatic void\nssl_renegotiation_cb(const SSL *ssl)\n{\n    VALUE ssl_obj, sslctx_obj, cb;\n\n    ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n    sslctx_obj = rb_attr_get(ssl_obj, id_i_context);\n    cb = rb_attr_get(sslctx_obj, id_i_renegotiation_cb);\n    if (NIL_P(cb)) return;\n\n    rb_funcallv(cb, id_call, 1, &ssl_obj);\n}\n\nstatic VALUE\nssl_npn_encode_protocol_i(RB_BLOCK_CALL_FUNC_ARGLIST(cur, encoded))\n{\n    int len = RSTRING_LENINT(cur);\n    char len_byte;\n    if (len < 1 || len > 255)\n        ossl_raise(eSSLError, \"Advertised protocol must have length 1..255\");\n    /* Encode the length byte */\n    len_byte = len;\n    rb_str_buf_cat(encoded, &len_byte, 1);\n    rb_str_buf_cat(encoded, RSTRING_PTR(cur), len);\n    return Qnil;\n}\n\nstatic VALUE\nssl_encode_npn_protocols(VALUE protocols)\n{\n    VALUE encoded = rb_str_new(NULL, 0);\n    rb_block_call(protocols, id_each, 0, 0, ssl_npn_encode_protocol_i, encoded);\n    return encoded;\n}\n\nstruct npn_select_cb_common_args {\n    VALUE cb;\n    const unsigned char *in;\n    unsigned inlen;\n};\n\nstatic VALUE\nnpn_select_cb_common_i(VALUE tmp)\n{\n    struct npn_select_cb_common_args *args = (void *)tmp;\n    const unsigned char *in = args->in, *in_end = in + args->inlen;\n    unsigned char l;\n    long len;\n    VALUE selected, protocols = rb_ary_new();\n\n    /* assume OpenSSL verifies this format */\n    /* The format is len_1|proto_1|...|len_n|proto_n */\n    while (in < in_end) {\n        l = *in++;\n        rb_ary_push(protocols, rb_str_new((const char *)in, l));\n        in += l;\n    }\n\n    selected = rb_funcallv(args->cb, id_call, 1, &protocols);\n    StringValue(selected);\n    len = RSTRING_LEN(selected);\n    if (len < 1 || len >= 256) {\n        ossl_raise(eSSLError, \"Selected protocol name must have length 1..255\");\n    }\n\n    return selected;\n}\n\nstatic int\nssl_npn_select_cb_common(SSL *ssl, VALUE cb, const unsigned char **out,\n                         unsigned char *outlen, const unsigned char *in,\n                         unsigned int inlen)\n{\n    VALUE selected;\n    int status;\n    struct npn_select_cb_common_args args;\n\n    args.cb = cb;\n    args.in = in;\n    args.inlen = inlen;\n\n    selected = rb_protect(npn_select_cb_common_i, (VALUE)&args, &status);\n    if (status) {\n        VALUE ssl_obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);\n\n        rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status));\n        return SSL_TLSEXT_ERR_ALERT_FATAL;\n    }\n\n    *out = (unsigned char *)RSTRING_PTR(selected);\n    *outlen = (unsigned char)RSTRING_LEN(selected);\n\n    return SSL_TLSEXT_ERR_OK;\n}\n\n#ifdef OSSL_USE_NEXTPROTONEG\nstatic int\nssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen,\n                     void *arg)\n{\n    VALUE protocols = rb_attr_get((VALUE)arg, id_npn_protocols_encoded);\n\n    *out = (const unsigned char *) RSTRING_PTR(protocols);\n    *outlen = RSTRING_LENINT(protocols);\n\n    return SSL_TLSEXT_ERR_OK;\n}\n\nstatic int\nssl_npn_select_cb(SSL *ssl, unsigned char **out, unsigned char *outlen,\n                  const unsigned char *in, unsigned int inlen, void *arg)\n{\n    VALUE sslctx_obj, cb;\n\n    sslctx_obj = (VALUE) arg;\n    cb = rb_attr_get(sslctx_obj, id_i_npn_select_cb);\n\n    return ssl_npn_select_cb_common(ssl, cb, (const unsigned char **)out,\n                                    outlen, in, inlen);\n}\n#endif\n\nstatic int\nssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen,\n                   const unsigned char *in, unsigned int inlen, void *arg)\n{\n    VALUE sslctx_obj, cb;\n\n    sslctx_obj = (VALUE) arg;\n    cb = rb_attr_get(sslctx_obj, id_i_alpn_select_cb);\n\n    return ssl_npn_select_cb_common(ssl, cb, out, outlen, in, inlen);\n}\n\n/* This function may serve as the entry point to support further callbacks. */\nstatic void\nssl_info_cb(const SSL *ssl, int where, int val)\n{\n    int is_server = SSL_is_server((SSL *)ssl);\n\n    if (is_server && where & SSL_CB_HANDSHAKE_START) {\n        ssl_renegotiation_cb(ssl);\n    }\n}\n\n/*\n * call-seq:\n *    ctx.options -> integer\n *\n * Gets various \\OpenSSL options.\n */\nstatic VALUE\nossl_sslctx_get_options(VALUE self)\n{\n    SSL_CTX *ctx;\n    GetSSLCTX(self, ctx);\n    /*\n     * Do explicit cast because SSL_CTX_get_options() returned (signed) long in\n     * OpenSSL before 1.1.0.\n     */\n    return ULONG2NUM((unsigned long)SSL_CTX_get_options(ctx));\n}\n\n/*\n * call-seq:\n *    ctx.options = integer\n *\n * Sets various \\OpenSSL options. The options are a bit field and can be\n * combined with the bitwise OR operator (<tt>|</tt>). Available options are\n * defined as constants in OpenSSL::SSL that begin with +OP_+.\n *\n * For backwards compatibility, passing +nil+ has the same effect as passing\n * OpenSSL::SSL::OP_ALL.\n *\n * See also man page SSL_CTX_set_options(3).\n */\nstatic VALUE\nossl_sslctx_set_options(VALUE self, VALUE options)\n{\n    SSL_CTX *ctx;\n\n    rb_check_frozen(self);\n    GetSSLCTX(self, ctx);\n\n    SSL_CTX_clear_options(ctx, SSL_CTX_get_options(ctx));\n\n    if (NIL_P(options)) {\n        SSL_CTX_set_options(ctx, SSL_OP_ALL);\n    } else {\n        SSL_CTX_set_options(ctx, NUM2ULONG(options));\n    }\n\n    return self;\n}\n\n/*\n * call-seq:\n *    ctx.setup => Qtrue # first time\n *    ctx.setup => nil # thereafter\n *\n * This method is called automatically when a new SSLSocket is created.\n * However, it is not thread-safe and must be called before creating\n * SSLSocket objects in a multi-threaded program.\n */\nstatic VALUE\nossl_sslctx_setup(VALUE self)\n{\n    SSL_CTX *ctx;\n    X509 *cert = NULL, *client_ca = NULL;\n    EVP_PKEY *key = NULL;\n    char *ca_path = NULL, *ca_file = NULL;\n    int verify_mode;\n    long i;\n    VALUE val;\n\n    if(OBJ_FROZEN(self)) return Qnil;\n    GetSSLCTX(self, ctx);\n\n#if !defined(OPENSSL_NO_DH)\n    if (!NIL_P(rb_attr_get(self, id_i_tmp_dh_callback))) {\n        SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);\n        SSL_CTX_set_dh_auto(ctx, 0);\n    }\n#endif\n\n#if !defined(OPENSSL_IS_AWSLC) /* AWS-LC has no support for TLS 1.3 PHA. */\n    SSL_CTX_set_post_handshake_auth(ctx, 1);\n#endif\n\n    val = rb_attr_get(self, id_i_cert_store);\n    if (!NIL_P(val)) {\n        X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */\n        SSL_CTX_set_cert_store(ctx, store);\n        X509_STORE_up_ref(store);\n    }\n\n    val = rb_attr_get(self, id_i_extra_chain_cert);\n    if(!NIL_P(val)){\n        rb_block_call(val, rb_intern(\"each\"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);\n    }\n\n    /* private key may be bundled in certificate file. */\n    val = rb_attr_get(self, id_i_cert);\n    cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */\n    val = rb_attr_get(self, id_i_key);\n    key = NIL_P(val) ? NULL : GetPrivPKeyPtr(val); /* NO DUP NEEDED */\n    if (cert && key) {\n        if (!SSL_CTX_use_certificate(ctx, cert)) {\n            /* Adds a ref => Safe to FREE */\n            ossl_raise(eSSLError, \"SSL_CTX_use_certificate\");\n        }\n        if (!SSL_CTX_use_PrivateKey(ctx, key)) {\n            /* Adds a ref => Safe to FREE */\n            ossl_raise(eSSLError, \"SSL_CTX_use_PrivateKey\");\n        }\n        if (!SSL_CTX_check_private_key(ctx)) {\n            ossl_raise(eSSLError, \"SSL_CTX_check_private_key\");\n        }\n    }\n\n    val = rb_attr_get(self, id_i_client_ca);\n    if(!NIL_P(val)){\n        if (RB_TYPE_P(val, T_ARRAY)) {\n            for(i = 0; i < RARRAY_LEN(val); i++){\n                client_ca = GetX509CertPtr(RARRAY_AREF(val, i));\n                if (!SSL_CTX_add_client_CA(ctx, client_ca)){\n                    /* Copies X509_NAME => FREE it. */\n                    ossl_raise(eSSLError, \"SSL_CTX_add_client_CA\");\n                }\n            }\n        }\n        else{\n            client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */\n            if (!SSL_CTX_add_client_CA(ctx, client_ca)){\n                /* Copies X509_NAME => FREE it. */\n                ossl_raise(eSSLError, \"SSL_CTX_add_client_CA\");\n            }\n        }\n    }\n\n    val = rb_attr_get(self, id_i_ca_file);\n    ca_file = NIL_P(val) ? NULL : StringValueCStr(val);\n    val = rb_attr_get(self, id_i_ca_path);\n    ca_path = NIL_P(val) ? NULL : StringValueCStr(val);\n#ifdef HAVE_SSL_CTX_LOAD_VERIFY_FILE\n    if (ca_file && !SSL_CTX_load_verify_file(ctx, ca_file))\n        ossl_raise(eSSLError, \"SSL_CTX_load_verify_file\");\n    if (ca_path && !SSL_CTX_load_verify_dir(ctx, ca_path))\n        ossl_raise(eSSLError, \"SSL_CTX_load_verify_dir\");\n#else\n    if (ca_file || ca_path) {\n        if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))\n            ossl_raise(eSSLError, \"SSL_CTX_load_verify_locations\");\n    }\n#endif\n\n    val = rb_attr_get(self, id_i_verify_mode);\n    verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);\n    SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);\n    if (RTEST(rb_attr_get(self, id_i_client_cert_cb)))\n        SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);\n\n    val = rb_attr_get(self, id_i_timeout);\n    if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));\n\n    val = rb_attr_get(self, id_i_verify_depth);\n    if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2INT(val));\n\n#ifdef OSSL_USE_NEXTPROTONEG\n    val = rb_attr_get(self, id_i_npn_protocols);\n    if (!NIL_P(val)) {\n        VALUE encoded = ssl_encode_npn_protocols(val);\n        rb_ivar_set(self, id_npn_protocols_encoded, encoded);\n        SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)self);\n        OSSL_Debug(\"SSL NPN advertise callback added\");\n    }\n    if (RTEST(rb_attr_get(self, id_i_npn_select_cb))) {\n        SSL_CTX_set_next_proto_select_cb(ctx, ssl_npn_select_cb, (void *) self);\n        OSSL_Debug(\"SSL NPN select callback added\");\n    }\n#endif\n\n    val = rb_attr_get(self, id_i_alpn_protocols);\n    if (!NIL_P(val)) {\n        VALUE rprotos = ssl_encode_npn_protocols(val);\n\n        /* returns 0 on success */\n        if (SSL_CTX_set_alpn_protos(ctx, (unsigned char *)RSTRING_PTR(rprotos),\n                                    RSTRING_LENINT(rprotos)))\n            ossl_raise(eSSLError, \"SSL_CTX_set_alpn_protos\");\n        OSSL_Debug(\"SSL ALPN values added\");\n    }\n    if (RTEST(rb_attr_get(self, id_i_alpn_select_cb))) {\n        SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);\n        OSSL_Debug(\"SSL ALPN select callback added\");\n    }\n\n    rb_obj_freeze(self);\n\n    val = rb_attr_get(self, id_i_session_id_context);\n    if (!NIL_P(val)){\n        StringValue(val);\n        if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),\n                                            RSTRING_LENINT(val))){\n            ossl_raise(eSSLError, \"SSL_CTX_set_session_id_context\");\n        }\n    }\n\n    if (RTEST(rb_attr_get(self, id_i_session_get_cb))) {\n        SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);\n        OSSL_Debug(\"SSL SESSION get callback added\");\n    }\n    if (RTEST(rb_attr_get(self, id_i_session_new_cb))) {\n        SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);\n        OSSL_Debug(\"SSL SESSION new callback added\");\n    }\n    if (RTEST(rb_attr_get(self, id_i_session_remove_cb))) {\n        SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);\n        OSSL_Debug(\"SSL SESSION remove callback added\");\n    }\n\n    val = rb_attr_get(self, id_i_servername_cb);\n    if (!NIL_P(val)) {\n        SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);\n        OSSL_Debug(\"SSL TLSEXT servername callback added\");\n    }\n\n#if !OSSL_IS_LIBRESSL\n    /*\n     * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements\n     * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see\n     * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6).\n     */\n    if (RTEST(rb_attr_get(self, id_i_keylog_cb))) {\n        SSL_CTX_set_keylog_callback(ctx, ossl_sslctx_keylog_cb);\n        OSSL_Debug(\"SSL keylog callback added\");\n    }\n#endif\n\n    return Qtrue;\n}\n\nstatic int\nparse_proto_version(VALUE str)\n{\n    int i;\n    static const struct {\n        const char *name;\n        int version;\n    } map[] = {\n        { \"SSL2\", SSL2_VERSION },\n        { \"SSL3\", SSL3_VERSION },\n        { \"TLS1\", TLS1_VERSION },\n        { \"TLS1_1\", TLS1_1_VERSION },\n        { \"TLS1_2\", TLS1_2_VERSION },\n        { \"TLS1_3\", TLS1_3_VERSION },\n    };\n\n    if (NIL_P(str))\n        return 0;\n    if (RB_INTEGER_TYPE_P(str))\n        return NUM2INT(str);\n\n    if (SYMBOL_P(str))\n        str = rb_sym2str(str);\n    StringValue(str);\n    for (i = 0; i < numberof(map); i++)\n        if (!strncmp(map[i].name, RSTRING_PTR(str), RSTRING_LEN(str)))\n            return map[i].version;\n    rb_raise(rb_eArgError, \"unrecognized version %+\"PRIsVALUE, str);\n}\n\n/*\n * call-seq:\n *    ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION\n *    ctx.min_version = :TLS1_2\n *    ctx.min_version = nil\n *\n * Sets the lower bound on the supported SSL/TLS protocol version. The\n * version may be specified by an integer constant named\n * OpenSSL::SSL::*_VERSION, a Symbol, or +nil+ which means \"any version\".\n *\n * === Example\n *   ctx = OpenSSL::SSL::SSLContext.new\n *   ctx.min_version = OpenSSL::SSL::TLS1_1_VERSION\n *   ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n *\n *   sock = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx)\n *   sock.connect # Initiates a connection using either TLS 1.1 or TLS 1.2\n */\nstatic VALUE\nossl_sslctx_set_min_version(VALUE self, VALUE v)\n{\n    SSL_CTX *ctx;\n    int version;\n\n    rb_check_frozen(self);\n    GetSSLCTX(self, ctx);\n    version = parse_proto_version(v);\n\n    if (!SSL_CTX_set_min_proto_version(ctx, version))\n        ossl_raise(eSSLError, \"SSL_CTX_set_min_proto_version\");\n    return v;\n}\n\n/*\n * call-seq:\n *    ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n *    ctx.max_version = :TLS1_2\n *    ctx.max_version = nil\n *\n * Sets the upper bound of the supported SSL/TLS protocol version. See\n * #min_version= for the possible values.\n */\nstatic VALUE\nossl_sslctx_set_max_version(VALUE self, VALUE v)\n{\n    SSL_CTX *ctx;\n    int version;\n\n    rb_check_frozen(self);\n    GetSSLCTX(self, ctx);\n    version = parse_proto_version(v);\n\n    if (!SSL_CTX_set_max_proto_version(ctx, version))\n        ossl_raise(eSSLError, \"SSL_CTX_set_max_proto_version\");\n    return v;\n}\n\nstatic VALUE\nossl_ssl_cipher_to_ary(const SSL_CIPHER *cipher)\n{\n    VALUE ary;\n    int bits, alg_bits;\n\n    ary = rb_ary_new2(4);\n    rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_name(cipher)));\n    rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_version(cipher)));\n    bits = SSL_CIPHER_get_bits(cipher, &alg_bits);\n    rb_ary_push(ary, INT2NUM(bits));\n    rb_ary_push(ary, INT2NUM(alg_bits));\n\n    return ary;\n}\n\n/*\n * call-seq:\n *    ctx.ciphers => [[name, version, bits, alg_bits], ...]\n *\n * The list of cipher suites configured for this context.\n */\nstatic VALUE\nossl_sslctx_get_ciphers(VALUE self)\n{\n    SSL_CTX *ctx;\n    STACK_OF(SSL_CIPHER) *ciphers;\n    const SSL_CIPHER *cipher;\n    VALUE ary;\n    int i, num;\n\n    GetSSLCTX(self, ctx);\n    ciphers = SSL_CTX_get_ciphers(ctx);\n    if (!ciphers)\n        return rb_ary_new();\n\n    num = sk_SSL_CIPHER_num(ciphers);\n    ary = rb_ary_new2(num);\n    for(i = 0; i < num; i++){\n        cipher = sk_SSL_CIPHER_value(ciphers, i);\n        rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher));\n    }\n    return ary;\n}\n\nstatic VALUE\nbuild_cipher_string(VALUE v)\n{\n    VALUE str, elem;\n\n    if (RB_TYPE_P(v, T_ARRAY)) {\n        str = rb_str_new(0, 0);\n        for (long i = 0; i < RARRAY_LEN(v); i++) {\n            elem = rb_ary_entry(v, i);\n            if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0);\n            elem = rb_String(elem);\n            rb_str_append(str, elem);\n            if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, \":\");\n        }\n    } else {\n        str = v;\n        StringValue(str);\n    }\n\n    return str;\n}\n\n/*\n * call-seq:\n *    ctx.ciphers = \"cipher1:cipher2:...\"\n *    ctx.ciphers = [name, ...]\n *    ctx.ciphers = [[name, version, bits, alg_bits], ...]\n *\n * Sets the list of available cipher suites for TLS 1.2 and below for this\n * context.\n *\n * Note in a server context some ciphers require the appropriate certificates.\n * For example, an RSA cipher suite can only be chosen when an RSA certificate\n * is available.\n *\n * This method does not affect TLS 1.3 connections. See also #ciphersuites=.\n */\nstatic VALUE\nossl_sslctx_set_ciphers(VALUE self, VALUE v)\n{\n    SSL_CTX *ctx;\n    VALUE str;\n\n    rb_check_frozen(self);\n    // Assigning nil is a no-op for compatibility\n    if (NIL_P(v))\n        return v;\n\n    str = build_cipher_string(v);\n\n    GetSSLCTX(self, ctx);\n    if (!SSL_CTX_set_cipher_list(ctx, StringValueCStr(str)))\n        ossl_raise(eSSLError, \"SSL_CTX_set_cipher_list\");\n\n    return v;\n}\n\n/*\n * call-seq:\n *    ctx.ciphersuites = \"cipher1:cipher2:...\"\n *    ctx.ciphersuites = [name, ...]\n *\n * Sets the list of available TLS 1.3 cipher suites for this context.\n */\nstatic VALUE\nossl_sslctx_set_ciphersuites(VALUE self, VALUE v)\n{\n    SSL_CTX *ctx;\n    VALUE str;\n\n    rb_check_frozen(self);\n    // Assigning nil is a no-op for compatibility\n    if (NIL_P(v))\n        return v;\n\n    str = build_cipher_string(v);\n\n    GetSSLCTX(self, ctx);\n    if (!SSL_CTX_set_ciphersuites(ctx, StringValueCStr(str)))\n        ossl_raise(eSSLError, \"SSL_CTX_set_ciphersuites\");\n\n    return v;\n}\n\n#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST\n/*\n * call-seq:\n *    ctx.sigalgs = \"sigalg1:sigalg2:...\"\n *\n * Sets the list of \"supported signature algorithms\" for this context.\n *\n * For a TLS client, the list is used in the \"signature_algorithms\" extension\n * in the ClientHello message. For a server, the list is used by OpenSSL to\n * determine the set of shared signature algorithms. OpenSSL will pick the most\n * appropriate one from it.\n *\n * See also #client_sigalgs= for the client authentication equivalent.\n */\nstatic VALUE\nossl_sslctx_set_sigalgs(VALUE self, VALUE v)\n{\n    SSL_CTX *ctx;\n\n    rb_check_frozen(self);\n    GetSSLCTX(self, ctx);\n\n    if (!SSL_CTX_set1_sigalgs_list(ctx, StringValueCStr(v)))\n        ossl_raise(eSSLError, \"SSL_CTX_set1_sigalgs_list\");\n\n    return v;\n}\n#endif\n\n#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST\n/*\n * call-seq:\n *    ctx.client_sigalgs = \"sigalg1:sigalg2:...\"\n *\n * Sets the list of \"supported signature algorithms\" for client authentication\n * for this context.\n *\n * For a TLS server, the list is sent to the client as part of the\n * CertificateRequest message.\n *\n * See also #sigalgs= for the server authentication equivalent.\n */\nstatic VALUE\nossl_sslctx_set_client_sigalgs(VALUE self, VALUE v)\n{\n    SSL_CTX *ctx;\n\n    rb_check_frozen(self);\n    GetSSLCTX(self, ctx);\n\n    if (!SSL_CTX_set1_client_sigalgs_list(ctx, StringValueCStr(v)))\n        ossl_raise(eSSLError, \"SSL_CTX_set1_client_sigalgs_list\");\n\n    return v;\n}\n#endif\n\n#ifndef OPENSSL_NO_DH\n/*\n * call-seq:\n *    ctx.tmp_dh = pkey\n *\n * Sets DH parameters used for ephemeral DH key exchange. This is relevant for\n * servers only.\n *\n * +pkey+ is an instance of OpenSSL::PKey::DH. Note that key components\n * contained in the key object, if any, are ignored. The server will always\n * generate a new key pair for each handshake.\n *\n * Added in version 3.0. See also the man page SSL_CTX_set0_tmp_dh_pkey(3).\n *\n * Example:\n *   ctx = OpenSSL::SSL::SSLContext.new\n *   ctx.tmp_dh = OpenSSL::DH.generate(2048)\n *   svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx)\n *   Thread.new { svr.accept }\n */\nstatic VALUE\nossl_sslctx_set_tmp_dh(VALUE self, VALUE arg)\n{\n    SSL_CTX *ctx;\n    EVP_PKEY *pkey;\n\n    rb_check_frozen(self);\n    GetSSLCTX(self, ctx);\n    pkey = GetPKeyPtr(arg);\n\n    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH)\n        rb_raise(eSSLError, \"invalid pkey type %s (expected DH)\",\n                 OBJ_nid2sn(EVP_PKEY_base_id(pkey)));\n#ifdef HAVE_SSL_CTX_SET0_TMP_DH_PKEY\n    if (!SSL_CTX_set0_tmp_dh_pkey(ctx, pkey))\n        ossl_raise(eSSLError, \"SSL_CTX_set0_tmp_dh_pkey\");\n    EVP_PKEY_up_ref(pkey);\n#else\n    if (!SSL_CTX_set_tmp_dh(ctx, EVP_PKEY_get0_DH(pkey)))\n        ossl_raise(eSSLError, \"SSL_CTX_set_tmp_dh\");\n#endif\n\n    // Turn off the \"auto\" DH parameters set by ossl_sslctx_s_alloc()\n    SSL_CTX_set_dh_auto(ctx, 0);\n\n    return arg;\n}\n#endif\n\n/*\n * call-seq:\n *    ctx.groups = groups_list\n *    ctx.ecdh_curves = groups_list\n *\n * Sets the list of supported groups for key agreement for this context.\n *\n * For a TLS client, the list is directly used in the \"supported_groups\"\n * extension. For a server, the list is used by OpenSSL to determine the set of\n * shared supported groups. OpenSSL will pick the most appropriate one from it.\n *\n * #ecdh_curves= is a deprecated alias for #groups=.\n *\n * See also the man page SSL_CTX_set1_groups_list(3).\n *\n * === Example\n *   ctx1 = OpenSSL::SSL::SSLContext.new\n *   ctx1.groups = \"X25519:P-256:P-224\"\n *   svr = OpenSSL::SSL::SSLServer.new(tcp_svr, ctx1)\n *   Thread.new { svr.accept }\n *\n *   ctx2 = OpenSSL::SSL::SSLContext.new\n *   ctx2.groups = \"P-256\"\n *   cli = OpenSSL::SSL::SSLSocket.new(tcp_sock, ctx2)\n *   cli.connect\n *\n *   p cli.tmp_key.group.curve_name\n *   # => \"prime256v1\" (is an alias for NIST P-256)\n */\nstatic VALUE\nossl_sslctx_set_groups(VALUE self, VALUE arg)\n{\n    SSL_CTX *ctx;\n\n    rb_check_frozen(self);\n    GetSSLCTX(self, ctx);\n    StringValueCStr(arg);\n\n    if (!SSL_CTX_set1_groups_list(ctx, RSTRING_PTR(arg)))\n        ossl_raise(eSSLError, \"SSL_CTX_set1_groups_list\");\n    return arg;\n}\n\n/*\n * call-seq:\n *    ctx.security_level -> Integer\n *\n * Returns the security level for the context.\n *\n * See also OpenSSL::SSL::SSLContext#security_level=.\n */\nstatic VALUE\nossl_sslctx_get_security_level(VALUE self)\n{\n    SSL_CTX *ctx;\n\n    GetSSLCTX(self, ctx);\n\n    return INT2NUM(SSL_CTX_get_security_level(ctx));\n}\n\n/*\n * call-seq:\n *    ctx.security_level = integer\n *\n * Sets the security level for the context. OpenSSL limits parameters according\n * to the level. The \"parameters\" include: ciphersuites, curves, key sizes,\n * certificate signature algorithms, protocol version and so on. For example,\n * level 1 rejects parameters offering below 80 bits of security, such as\n * ciphersuites using MD5 for the MAC or RSA keys shorter than 1024 bits.\n *\n * Note that attempts to set such parameters with insufficient security are\n * also blocked. You need to lower the level first.\n *\n * This feature is not supported in OpenSSL < 1.1.0, and setting the level to\n * other than 0 will raise NotImplementedError. Level 0 means everything is\n * permitted, the same behavior as previous versions of OpenSSL.\n *\n * See the manpage of SSL_CTX_set_security_level(3) for details.\n */\nstatic VALUE\nossl_sslctx_set_security_level(VALUE self, VALUE value)\n{\n    SSL_CTX *ctx;\n\n    rb_check_frozen(self);\n    GetSSLCTX(self, ctx);\n\n    SSL_CTX_set_security_level(ctx, NUM2INT(value));\n\n    return value;\n}\n\n#ifdef SSL_MODE_SEND_FALLBACK_SCSV\n/*\n * call-seq:\n *    ctx.enable_fallback_scsv() => nil\n *\n * Activate TLS_FALLBACK_SCSV for this context.\n * See RFC 7507.\n */\nstatic VALUE\nossl_sslctx_enable_fallback_scsv(VALUE self)\n{\n    SSL_CTX *ctx;\n\n    GetSSLCTX(self, ctx);\n    SSL_CTX_set_mode(ctx, SSL_MODE_SEND_FALLBACK_SCSV);\n\n    return Qnil;\n}\n#endif\n\n/*\n * call-seq:\n *    ctx.add_certificate(certificate, pkey [, extra_certs]) -> self\n *\n * Adds a certificate to the context. _pkey_ must be a corresponding private\n * key with _certificate_.\n *\n * Multiple certificates with different public key type can be added by\n * repeated calls of this method, and OpenSSL will choose the most appropriate\n * certificate during the handshake.\n *\n * #cert=, #key=, and #extra_chain_cert= are old accessor methods for setting\n * certificate and internally call this method.\n *\n * === Parameters\n * _certificate_::\n *   A certificate. An instance of OpenSSL::X509::Certificate.\n * _pkey_::\n *   The private key for _certificate_. An instance of OpenSSL::PKey::PKey.\n * _extra_certs_::\n *   Optional. An array of OpenSSL::X509::Certificate. When sending a\n *   certificate chain, the certificates specified by this are sent following\n *   _certificate_, in the order in the array.\n *\n * === Example\n *   rsa_cert = OpenSSL::X509::Certificate.new(...)\n *   rsa_pkey = OpenSSL::PKey.read(...)\n *   ca_intermediate_cert = OpenSSL::X509::Certificate.new(...)\n *   ctx.add_certificate(rsa_cert, rsa_pkey, [ca_intermediate_cert])\n *\n *   ecdsa_cert = ...\n *   ecdsa_pkey = ...\n *   another_ca_cert = ...\n *   ctx.add_certificate(ecdsa_cert, ecdsa_pkey, [another_ca_cert])\n */\nstatic VALUE\nossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self)\n{\n    VALUE cert, key, extra_chain_ary;\n    SSL_CTX *ctx;\n    X509 *x509;\n    STACK_OF(X509) *extra_chain = NULL;\n    EVP_PKEY *pkey, *pub_pkey;\n\n    GetSSLCTX(self, ctx);\n    rb_scan_args(argc, argv, \"21\", &cert, &key, &extra_chain_ary);\n    rb_check_frozen(self);\n    x509 = GetX509CertPtr(cert);\n    pkey = GetPrivPKeyPtr(key);\n\n    /*\n     * The reference counter is bumped, and decremented immediately.\n     * X509_get0_pubkey() is only available in OpenSSL >= 1.1.0.\n     */\n    pub_pkey = X509_get_pubkey(x509);\n    EVP_PKEY_free(pub_pkey);\n    if (!pub_pkey)\n        rb_raise(rb_eArgError, \"certificate does not contain public key\");\n    if (EVP_PKEY_eq(pub_pkey, pkey) != 1)\n        rb_raise(rb_eArgError, \"public key mismatch\");\n\n    if (argc >= 3)\n        extra_chain = ossl_x509_ary2sk(extra_chain_ary);\n\n    if (!SSL_CTX_use_certificate(ctx, x509)) {\n        sk_X509_pop_free(extra_chain, X509_free);\n        ossl_raise(eSSLError, \"SSL_CTX_use_certificate\");\n    }\n    if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {\n        sk_X509_pop_free(extra_chain, X509_free);\n        ossl_raise(eSSLError, \"SSL_CTX_use_PrivateKey\");\n    }\n    if (extra_chain && !SSL_CTX_set0_chain(ctx, extra_chain)) {\n        sk_X509_pop_free(extra_chain, X509_free);\n        ossl_raise(eSSLError, \"SSL_CTX_set0_chain\");\n    }\n    return self;\n}\n\n/*\n *  call-seq:\n *     ctx.session_add(session) -> true | false\n *\n * Adds _session_ to the session cache.\n */\nstatic VALUE\nossl_sslctx_session_add(VALUE self, VALUE arg)\n{\n    SSL_CTX *ctx;\n    SSL_SESSION *sess;\n\n    GetSSLCTX(self, ctx);\n    GetSSLSession(arg, sess);\n\n    return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse;\n}\n\n/*\n *  call-seq:\n *     ctx.session_remove(session) -> true | false\n *\n * Removes _session_ from the session cache.\n */\nstatic VALUE\nossl_sslctx_session_remove(VALUE self, VALUE arg)\n{\n    SSL_CTX *ctx;\n    SSL_SESSION *sess;\n\n    GetSSLCTX(self, ctx);\n    GetSSLSession(arg, sess);\n\n    return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse;\n}\n\n/*\n *  call-seq:\n *     ctx.session_cache_mode -> Integer\n *\n * The current session cache mode.\n */\nstatic VALUE\nossl_sslctx_get_session_cache_mode(VALUE self)\n{\n    SSL_CTX *ctx;\n\n    GetSSLCTX(self, ctx);\n\n    return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx));\n}\n\n/*\n *  call-seq:\n *     ctx.session_cache_mode=(integer) -> Integer\n *\n * Sets the SSL session cache mode.  Bitwise-or together the desired\n * SESSION_CACHE_* constants to set.  See SSL_CTX_set_session_cache_mode(3) for\n * details.\n */\nstatic VALUE\nossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)\n{\n    SSL_CTX *ctx;\n\n    GetSSLCTX(self, ctx);\n\n    SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg));\n\n    return arg;\n}\n\n/*\n *  call-seq:\n *     ctx.session_cache_size -> Integer\n *\n * Returns the current session cache size.  Zero is used to represent an\n * unlimited cache size.\n */\nstatic VALUE\nossl_sslctx_get_session_cache_size(VALUE self)\n{\n    SSL_CTX *ctx;\n\n    GetSSLCTX(self, ctx);\n\n    return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx));\n}\n\n/*\n *  call-seq:\n *     ctx.session_cache_size=(integer) -> Integer\n *\n * Sets the session cache size.  Returns the previously valid session cache\n * size.  Zero is used to represent an unlimited session cache size.\n */\nstatic VALUE\nossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)\n{\n    SSL_CTX *ctx;\n\n    GetSSLCTX(self, ctx);\n\n    SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg));\n\n    return arg;\n}\n\n/*\n *  call-seq:\n *     ctx.session_cache_stats -> Hash\n *\n * Returns a Hash containing the following keys:\n *\n * :accept:: Number of started SSL/TLS handshakes in server mode\n * :accept_good:: Number of established SSL/TLS sessions in server mode\n * :accept_renegotiate:: Number of start renegotiations in server mode\n * :cache_full:: Number of sessions that were removed due to cache overflow\n * :cache_hits:: Number of successfully reused connections\n * :cache_misses:: Number of sessions proposed by clients that were not found\n *                 in the cache\n * :cache_num:: Number of sessions in the internal session cache\n * :cb_hits:: Number of sessions retrieved from the external cache in server\n *            mode\n * :connect:: Number of started SSL/TLS handshakes in client mode\n * :connect_good:: Number of established SSL/TLS sessions in client mode\n * :connect_renegotiate:: Number of start renegotiations in client mode\n * :timeouts:: Number of sessions proposed by clients that were found in the\n *             cache but had expired due to timeouts\n */\nstatic VALUE\nossl_sslctx_get_session_cache_stats(VALUE self)\n{\n    SSL_CTX *ctx;\n    VALUE hash;\n\n    GetSSLCTX(self, ctx);\n\n    hash = rb_hash_new();\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"cache_num\")), LONG2NUM(SSL_CTX_sess_number(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"connect\")), LONG2NUM(SSL_CTX_sess_connect(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"connect_good\")), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"connect_renegotiate\")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"accept\")), LONG2NUM(SSL_CTX_sess_accept(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"accept_good\")), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"accept_renegotiate\")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"cache_hits\")), LONG2NUM(SSL_CTX_sess_hits(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"cb_hits\")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"cache_misses\")), LONG2NUM(SSL_CTX_sess_misses(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"cache_full\")), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));\n    rb_hash_aset(hash, ID2SYM(rb_intern(\"timeouts\")), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));\n\n    return hash;\n}\n\n\n/*\n *  call-seq:\n *     ctx.flush_sessions(time) -> self\n *\n * Removes sessions in the internal cache that have expired at _time_.\n */\nstatic VALUE\nossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)\n{\n    VALUE arg1;\n    SSL_CTX *ctx;\n    time_t tm = 0;\n\n    rb_scan_args(argc, argv, \"01\", &arg1);\n\n    GetSSLCTX(self, ctx);\n\n    if (NIL_P(arg1)) {\n        tm = time(0);\n    } else if (rb_obj_is_instance_of(arg1, rb_cTime)) {\n        tm = NUM2LONG(rb_funcall(arg1, rb_intern(\"to_i\"), 0));\n    } else {\n        ossl_raise(rb_eArgError, \"arg must be Time or nil\");\n    }\n\n    SSL_CTX_flush_sessions(ctx, (long)tm);\n\n    return self;\n}\n\n/*\n * SSLSocket class\n */\nstatic inline int\nssl_started(SSL *ssl)\n{\n    /* BIO is created through ossl_ssl_setup(), called by #connect or #accept */\n    return SSL_get_rbio(ssl) != NULL;\n}\n\nstatic void\nossl_ssl_mark(void *ptr)\n{\n    SSL *ssl = ptr;\n    rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx));\n}\n\nstatic void\nossl_ssl_free(void *ssl)\n{\n    SSL_free(ssl);\n}\n\nconst rb_data_type_t ossl_ssl_type = {\n    \"OpenSSL/SSL\",\n    {\n        ossl_ssl_mark, ossl_ssl_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_ssl_s_alloc(VALUE klass)\n{\n    return TypedData_Wrap_Struct(klass, &ossl_ssl_type, NULL);\n}\n\nstatic VALUE\npeer_ip_address(VALUE io)\n{\n    VALUE remote_address = rb_funcall(io, rb_intern(\"remote_address\"), 0);\n\n    return rb_funcall(remote_address, rb_intern(\"inspect_sockaddr\"), 0);\n}\n\nstatic VALUE\nfallback_peer_ip_address(VALUE self, VALUE exc)\n{\n    return rb_str_new_cstr(\"(null)\");\n}\n\nstatic VALUE\npeeraddr_ip_str(VALUE io)\n{\n    return rb_rescue2(peer_ip_address, io, fallback_peer_ip_address, Qnil,\n                      rb_eSystemCallError, (VALUE)0);\n}\n\n/*\n * call-seq:\n *    SSLSocket.new(io) => aSSLSocket\n *    SSLSocket.new(io, ctx) => aSSLSocket\n *    SSLSocket.new(io, ctx, sync_close:) => aSSLSocket\n *\n * Creates a new SSL socket from _io_ which must be a real IO object (not an\n * IO-like object that responds to read/write).\n *\n * If _ctx_ is provided the SSL Sockets initial params will be taken from\n * the context.\n *\n * The optional _sync_close_ keyword parameter sets the _sync_close_ instance\n * variable. Setting this to +true+ will cause the underlying socket to be\n * closed when the SSL/TLS connection is shut down.\n *\n * The OpenSSL::Buffering module provides additional IO methods.\n *\n * This method will freeze the SSLContext if one is provided;\n * however, session management is still allowed in the frozen SSLContext.\n */\nstatic VALUE\nossl_ssl_initialize(int argc, VALUE *argv, VALUE self)\n{\n    static ID kw_ids[1];\n    VALUE kw_args[1];\n    VALUE opts;\n\n    VALUE io, v_ctx;\n    SSL *ssl;\n    SSL_CTX *ctx;\n\n    TypedData_Get_Struct(self, SSL, &ossl_ssl_type, ssl);\n    if (ssl)\n        ossl_raise(eSSLError, \"SSL already initialized\");\n\n    if (rb_scan_args(argc, argv, \"11:\", &io, &v_ctx, &opts) == 1)\n        v_ctx = rb_funcall(cSSLContext, rb_intern(\"new\"), 0);\n\n    if (!kw_ids[0]) {\n        kw_ids[0] = rb_intern_const(\"sync_close\");\n    }\n\n    rb_get_kwargs(opts, kw_ids, 0, 1, kw_args);\n    if (kw_args[0] != Qundef) {\n        rb_ivar_set(self, id_i_sync_close, kw_args[0]);\n    }\n\n    GetSSLCTX(v_ctx, ctx);\n    rb_ivar_set(self, id_i_context, v_ctx);\n    ossl_sslctx_setup(v_ctx);\n\n    if (rb_respond_to(io, rb_intern(\"nonblock=\")))\n        rb_funcall(io, rb_intern(\"nonblock=\"), 1, Qtrue);\n    Check_Type(io, T_FILE);\n    rb_ivar_set(self, id_i_io, io);\n\n    ssl = SSL_new(ctx);\n    if (!ssl)\n        ossl_raise(eSSLError, NULL);\n    RTYPEDDATA_DATA(self) = ssl;\n\n    if (!SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self))\n        ossl_raise(eSSLError, \"SSL_set_ex_data\");\n    SSL_set_info_callback(ssl, ssl_info_cb);\n\n    rb_call_super(0, NULL);\n\n    return self;\n}\n\n#ifndef HAVE_RB_IO_DESCRIPTOR\nstatic int\nio_descriptor_fallback(VALUE io)\n{\n    rb_io_t *fptr;\n    GetOpenFile(io, fptr);\n    return fptr->fd;\n}\n#define rb_io_descriptor io_descriptor_fallback\n#endif\n\nstatic VALUE\nossl_ssl_setup(VALUE self)\n{\n    VALUE io;\n    SSL *ssl;\n    rb_io_t *fptr;\n\n    GetSSL(self, ssl);\n    if (ssl_started(ssl))\n        return Qtrue;\n\n    io = rb_attr_get(self, id_i_io);\n    GetOpenFile(io, fptr);\n    rb_io_check_readable(fptr);\n    rb_io_check_writable(fptr);\n    if (!SSL_set_fd(ssl, TO_SOCKET(rb_io_descriptor(io))))\n        ossl_raise(eSSLError, \"SSL_set_fd\");\n\n    return Qtrue;\n}\n\nstatic int\nerrno_mapped(void)\n{\n#ifdef _WIN32\n    return rb_w32_map_errno(WSAGetLastError());\n#else\n    return errno;\n#endif\n}\n\nstatic void\nwrite_would_block(int nonblock)\n{\n    if (nonblock)\n        ossl_raise(eSSLErrorWaitWritable, \"write would block\");\n}\n\nstatic void\nread_would_block(int nonblock)\n{\n    if (nonblock)\n        ossl_raise(eSSLErrorWaitReadable, \"read would block\");\n}\n\nstatic int\nno_exception_p(VALUE opts)\n{\n    if (RB_TYPE_P(opts, T_HASH) &&\n          rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse)\n        return 1;\n    return 0;\n}\n\n// Provided by Ruby 3.2.0 and later in order to support the default IO#timeout.\n#ifndef RUBY_IO_TIMEOUT_DEFAULT\n#define RUBY_IO_TIMEOUT_DEFAULT Qnil\n#endif\n\n#ifdef HAVE_RB_IO_TIMEOUT\n#define IO_TIMEOUT_ERROR rb_eIOTimeoutError\n#else\n#define IO_TIMEOUT_ERROR rb_eIOError\n#endif\n\n\nstatic void\nio_wait_writable(VALUE io)\n{\n#ifdef HAVE_RB_IO_MAYBE_WAIT\n    if (!rb_io_wait(io, INT2NUM(RUBY_IO_WRITABLE), RUBY_IO_TIMEOUT_DEFAULT)) {\n        rb_raise(IO_TIMEOUT_ERROR, \"Timed out while waiting to become writable!\");\n    }\n#else\n    rb_io_t *fptr;\n    GetOpenFile(io, fptr);\n    rb_thread_fd_writable(fptr->fd);\n#endif\n}\n\nstatic void\nio_wait_readable(VALUE io)\n{\n#ifdef HAVE_RB_IO_MAYBE_WAIT\n    if (!rb_io_wait(io, INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT)) {\n        rb_raise(IO_TIMEOUT_ERROR, \"Timed out while waiting to become readable!\");\n    }\n#else\n    rb_io_t *fptr;\n    GetOpenFile(io, fptr);\n    rb_thread_wait_fd(fptr->fd);\n#endif\n}\n\nstatic VALUE\nossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)\n{\n    SSL *ssl;\n    VALUE cb_state;\n    int nonblock = opts != Qfalse;\n\n    rb_ivar_set(self, ID_callback_state, Qnil);\n\n    GetSSL(self, ssl);\n\n    VALUE io = rb_attr_get(self, id_i_io);\n    for (;;) {\n        int ret = func(ssl);\n        int saved_errno = errno_mapped();\n\n        cb_state = rb_attr_get(self, ID_callback_state);\n        if (!NIL_P(cb_state)) {\n            /* must cleanup OpenSSL error stack before re-raising */\n            ossl_clear_error();\n            rb_jump_tag(NUM2INT(cb_state));\n        }\n\n        if (ret > 0)\n            break;\n\n        int code = SSL_get_error(ssl, ret);\n        switch (code) {\n          case SSL_ERROR_WANT_WRITE:\n            if (no_exception_p(opts)) { return sym_wait_writable; }\n            write_would_block(nonblock);\n            io_wait_writable(io);\n            continue;\n          case SSL_ERROR_WANT_READ:\n            if (no_exception_p(opts)) { return sym_wait_readable; }\n            read_would_block(nonblock);\n            io_wait_readable(io);\n            continue;\n          case SSL_ERROR_SYSCALL:\n#ifdef __APPLE__\n            /* See ossl_ssl_write_internal() */\n            if (saved_errno == EPROTOTYPE)\n                continue;\n#endif\n            if (saved_errno)\n                rb_exc_raise(rb_syserr_new(saved_errno, funcname));\n            /* fallthrough */\n          default: {\n              VALUE error_append = Qnil;\n#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED)\n              unsigned long err = ERR_peek_last_error();\n              if (ERR_GET_LIB(err) == ERR_LIB_SSL &&\n                  ERR_GET_REASON(err) == SSL_R_CERTIFICATE_VERIFY_FAILED) {\n                  const char *err_msg = ERR_reason_error_string(err),\n                        *verify_msg = X509_verify_cert_error_string(SSL_get_verify_result(ssl));\n                  if (!err_msg)\n                      err_msg = \"(null)\";\n                  if (!verify_msg)\n                      verify_msg = \"(null)\";\n                  ossl_clear_error(); /* let ossl_raise() not append message */\n                  error_append = rb_sprintf(\": %s (%s)\", err_msg, verify_msg);\n              }\n#endif\n              ossl_raise(eSSLError,\n                         \"%s%s returned=%d errno=%d peeraddr=%\"PRIsVALUE\" state=%s%\"PRIsVALUE,\n                         funcname,\n                         code == SSL_ERROR_SYSCALL ? \" SYSCALL\" : \"\",\n                         code,\n                         saved_errno,\n                         peeraddr_ip_str(io),\n                         SSL_state_string_long(ssl),\n                         error_append);\n          }\n        }\n    }\n\n    return self;\n}\n\n/*\n * call-seq:\n *    ssl.connect => self\n *\n * Initiates an SSL/TLS handshake with a server.\n */\nstatic VALUE\nossl_ssl_connect(VALUE self)\n{\n    ossl_ssl_setup(self);\n\n    return ossl_start_ssl(self, SSL_connect, \"SSL_connect\", Qfalse);\n}\n\n/*\n * call-seq:\n *    ssl.connect_nonblock([options]) => self\n *\n * Initiates the SSL/TLS handshake as a client in non-blocking manner.\n *\n *   # emulates blocking connect\n *   begin\n *     ssl.connect_nonblock\n *   rescue IO::WaitReadable\n *     IO.select([s2])\n *     retry\n *   rescue IO::WaitWritable\n *     IO.select(nil, [s2])\n *     retry\n *   end\n *\n * By specifying a keyword argument _exception_ to +false+, you can indicate\n * that connect_nonblock should not raise an IO::WaitReadable or\n * IO::WaitWritable exception, but return the symbol +:wait_readable+ or\n * +:wait_writable+ instead.\n */\nstatic VALUE\nossl_ssl_connect_nonblock(int argc, VALUE *argv, VALUE self)\n{\n    VALUE opts;\n    rb_scan_args(argc, argv, \"0:\", &opts);\n\n    ossl_ssl_setup(self);\n\n    return ossl_start_ssl(self, SSL_connect, \"SSL_connect\", opts);\n}\n\n/*\n * call-seq:\n *    ssl.accept => self\n *\n * Waits for a SSL/TLS client to initiate a handshake.\n */\nstatic VALUE\nossl_ssl_accept(VALUE self)\n{\n    ossl_ssl_setup(self);\n\n    return ossl_start_ssl(self, SSL_accept, \"SSL_accept\", Qfalse);\n}\n\n/*\n * call-seq:\n *    ssl.accept_nonblock([options]) => self\n *\n * Initiates the SSL/TLS handshake as a server in non-blocking manner.\n *\n *   # emulates blocking accept\n *   begin\n *     ssl.accept_nonblock\n *   rescue IO::WaitReadable\n *     IO.select([s2])\n *     retry\n *   rescue IO::WaitWritable\n *     IO.select(nil, [s2])\n *     retry\n *   end\n *\n * By specifying a keyword argument _exception_ to +false+, you can indicate\n * that accept_nonblock should not raise an IO::WaitReadable or\n * IO::WaitWritable exception, but return the symbol +:wait_readable+ or\n * +:wait_writable+ instead.\n */\nstatic VALUE\nossl_ssl_accept_nonblock(int argc, VALUE *argv, VALUE self)\n{\n    VALUE opts;\n\n    rb_scan_args(argc, argv, \"0:\", &opts);\n    ossl_ssl_setup(self);\n\n    return ossl_start_ssl(self, SSL_accept, \"SSL_accept\", opts);\n}\n\nstatic VALUE\nossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)\n{\n    SSL *ssl;\n    int ilen;\n    VALUE len, str, cb_state;\n    VALUE opts = Qnil;\n\n    if (nonblock) {\n        rb_scan_args(argc, argv, \"11:\", &len, &str, &opts);\n    } else {\n        rb_scan_args(argc, argv, \"11\", &len, &str);\n    }\n    GetSSL(self, ssl);\n    if (!ssl_started(ssl))\n        rb_raise(eSSLError, \"SSL session is not started yet\");\n\n    ilen = NUM2INT(len);\n    if (NIL_P(str))\n        str = rb_str_new(0, ilen);\n    else {\n        StringValue(str);\n        if (RSTRING_LEN(str) >= ilen)\n            rb_str_modify(str);\n        else\n            rb_str_modify_expand(str, ilen - RSTRING_LEN(str));\n    }\n\n    if (ilen == 0) {\n        rb_str_set_len(str, 0);\n        return str;\n    }\n\n    VALUE io = rb_attr_get(self, id_i_io);\n\n    for (;;) {\n        rb_str_locktmp(str);\n        int nread = SSL_read(ssl, RSTRING_PTR(str), ilen);\n        int saved_errno = errno_mapped();\n        rb_str_unlocktmp(str);\n\n        cb_state = rb_attr_get(self, ID_callback_state);\n        if (!NIL_P(cb_state)) {\n            rb_ivar_set(self, ID_callback_state, Qnil);\n            ossl_clear_error();\n            rb_jump_tag(NUM2INT(cb_state));\n        }\n\n        switch (SSL_get_error(ssl, nread)) {\n          case SSL_ERROR_NONE:\n            rb_str_set_len(str, nread);\n            return str;\n          case SSL_ERROR_ZERO_RETURN:\n            if (no_exception_p(opts)) { return Qnil; }\n            rb_eof_error();\n          case SSL_ERROR_WANT_WRITE:\n            if (nonblock) {\n                if (no_exception_p(opts)) { return sym_wait_writable; }\n                write_would_block(nonblock);\n            }\n            io_wait_writable(io);\n            break;\n          case SSL_ERROR_WANT_READ:\n            if (nonblock) {\n                if (no_exception_p(opts)) { return sym_wait_readable; }\n                read_would_block(nonblock);\n            }\n            io_wait_readable(io);\n            break;\n          case SSL_ERROR_SYSCALL:\n            if (!ERR_peek_error()) {\n                if (saved_errno)\n                    rb_exc_raise(rb_syserr_new(saved_errno, \"SSL_read\"));\n                else {\n                    /*\n                     * The underlying BIO returned 0. This is actually a\n                     * protocol error. But unfortunately, not all\n                     * implementations cleanly shutdown the TLS connection\n                     * but just shutdown/close the TCP connection. So report\n                     * EOF for now...\n                     */\n                    if (no_exception_p(opts)) { return Qnil; }\n                    rb_eof_error();\n                }\n            }\n            /* fall through */\n          default:\n            ossl_raise(eSSLError, \"SSL_read\");\n        }\n\n        // Ensure the buffer is not modified during io_wait_*able()\n        rb_str_modify(str);\n        if (rb_str_capacity(str) < (size_t)ilen)\n            rb_raise(eSSLError, \"read buffer was modified\");\n    }\n}\n\n/*\n * call-seq:\n *    ssl.sysread(length) => string\n *    ssl.sysread(length, buffer) => buffer\n *\n * Reads _length_ bytes from the SSL connection.  If a pre-allocated _buffer_\n * is provided the data will be written into it.\n */\nstatic VALUE\nossl_ssl_read(int argc, VALUE *argv, VALUE self)\n{\n    return ossl_ssl_read_internal(argc, argv, self, 0);\n}\n\n/*\n * call-seq:\n *    ssl.sysread_nonblock(length) => string\n *    ssl.sysread_nonblock(length, buffer) => buffer\n *    ssl.sysread_nonblock(length[, buffer [, opts]) => buffer\n *\n * A non-blocking version of #sysread.  Raises an SSLError if reading would\n * block.  If \"exception: false\" is passed, this method returns a symbol of\n * :wait_readable, :wait_writable, or nil, rather than raising an exception.\n *\n * Reads _length_ bytes from the SSL connection.  If a pre-allocated _buffer_\n * is provided the data will be written into it.\n */\nstatic VALUE\nossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)\n{\n    return ossl_ssl_read_internal(argc, argv, self, 1);\n}\n\nstatic VALUE\nossl_ssl_write_internal_safe(VALUE _args)\n{\n    VALUE *args = (VALUE*)_args;\n    VALUE self = args[0];\n    VALUE str = args[1];\n    VALUE opts = args[2];\n\n    SSL *ssl;\n    rb_io_t *fptr;\n    int num, nonblock = opts != Qfalse;\n    VALUE cb_state;\n\n    GetSSL(self, ssl);\n    if (!ssl_started(ssl))\n        rb_raise(eSSLError, \"SSL session is not started yet\");\n\n    VALUE io = rb_attr_get(self, id_i_io);\n    GetOpenFile(io, fptr);\n\n    /* SSL_write(3ssl) manpage states num == 0 is undefined */\n    num = RSTRING_LENINT(str);\n    if (num == 0)\n        return INT2FIX(0);\n\n    for (;;) {\n        int nwritten = SSL_write(ssl, RSTRING_PTR(str), num);\n        int saved_errno = errno_mapped();\n\n        cb_state = rb_attr_get(self, ID_callback_state);\n        if (!NIL_P(cb_state)) {\n            rb_ivar_set(self, ID_callback_state, Qnil);\n            ossl_clear_error();\n            rb_jump_tag(NUM2INT(cb_state));\n        }\n\n        switch (SSL_get_error(ssl, nwritten)) {\n          case SSL_ERROR_NONE:\n            return INT2NUM(nwritten);\n          case SSL_ERROR_WANT_WRITE:\n            if (no_exception_p(opts)) { return sym_wait_writable; }\n            write_would_block(nonblock);\n            io_wait_writable(io);\n            continue;\n          case SSL_ERROR_WANT_READ:\n            if (no_exception_p(opts)) { return sym_wait_readable; }\n            read_would_block(nonblock);\n            io_wait_readable(io);\n            continue;\n          case SSL_ERROR_SYSCALL:\n#ifdef __APPLE__\n            /*\n             * It appears that send syscall can return EPROTOTYPE if the\n             * socket is being torn down. Retry to get a proper errno to\n             * make the error handling in line with the socket library.\n             * [Bug #14713] https://bugs.ruby-lang.org/issues/14713\n             */\n            if (saved_errno == EPROTOTYPE)\n                continue;\n#endif\n            if (saved_errno)\n                rb_exc_raise(rb_syserr_new(saved_errno, \"SSL_write\"));\n            /* fallthrough */\n          default:\n            ossl_raise(eSSLError, \"SSL_write\");\n        }\n    }\n}\n\n\nstatic VALUE\nossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts)\n{\n    StringValue(str);\n    int frozen = RB_OBJ_FROZEN(str);\n    if (!frozen) {\n        rb_str_locktmp(str);\n    }\n    int state;\n    VALUE args[3] = {self, str, opts};\n    VALUE result = rb_protect(ossl_ssl_write_internal_safe, (VALUE)args, &state);\n    if (!frozen) {\n        rb_str_unlocktmp(str);\n    }\n\n    if (state) {\n        rb_jump_tag(state);\n    }\n    return result;\n}\n\n/*\n * call-seq:\n *    ssl.syswrite(string) => Integer\n *\n * Writes _string_ to the SSL connection.\n */\nstatic VALUE\nossl_ssl_write(VALUE self, VALUE str)\n{\n    return ossl_ssl_write_internal(self, str, Qfalse);\n}\n\n/*\n * call-seq:\n *    ssl.syswrite_nonblock(string) => Integer\n *\n * Writes _string_ to the SSL connection in a non-blocking manner.  Raises an\n * SSLError if writing would block.\n */\nstatic VALUE\nossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self)\n{\n    VALUE str, opts;\n\n    rb_scan_args(argc, argv, \"1:\", &str, &opts);\n\n    return ossl_ssl_write_internal(self, str, opts);\n}\n\n/*\n * call-seq:\n *    ssl.stop => nil\n *\n * Sends \"close notify\" to the peer and tries to shut down the SSL connection\n * gracefully.\n */\nstatic VALUE\nossl_ssl_stop(VALUE self)\n{\n    SSL *ssl;\n    int ret;\n\n    GetSSL(self, ssl);\n    if (!ssl_started(ssl))\n        return Qnil;\n    ret = SSL_shutdown(ssl);\n    if (ret == 1) /* Have already received close_notify */\n        return Qnil;\n    if (ret == 0) /* Sent close_notify, but we don't wait for reply */\n        return Qnil;\n\n    /*\n     * XXX: Something happened. Possibly it failed because the underlying socket\n     * is not writable/readable, since it is in non-blocking mode. We should do\n     * some proper error handling using SSL_get_error() and maybe retry, but we\n     * can't block here. Give up for now.\n     */\n    ossl_clear_error();\n    return Qnil;\n}\n\n/*\n * call-seq:\n *    ssl.cert => cert or nil\n *\n * The X509 certificate for this socket endpoint.\n */\nstatic VALUE\nossl_ssl_get_cert(VALUE self)\n{\n    SSL *ssl;\n    X509 *cert = NULL;\n\n    GetSSL(self, ssl);\n\n    /*\n     * Is this OpenSSL bug? Should add a ref?\n     * TODO: Ask for.\n     */\n    cert = SSL_get_certificate(ssl); /* NO DUPs => DON'T FREE. */\n\n    if (!cert) {\n        return Qnil;\n    }\n    return ossl_x509_new(cert);\n}\n\n/*\n * call-seq:\n *    ssl.peer_cert => cert or nil\n *\n * The X509 certificate for this socket's peer.\n */\nstatic VALUE\nossl_ssl_get_peer_cert(VALUE self)\n{\n    SSL *ssl;\n    X509 *cert = NULL;\n    VALUE obj;\n\n    GetSSL(self, ssl);\n\n    cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */\n\n    if (!cert) {\n        return Qnil;\n    }\n    obj = ossl_x509_new(cert);\n    X509_free(cert);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    ssl.peer_cert_chain => [cert, ...] or nil\n *\n * The X509 certificate chain for this socket's peer.\n */\nstatic VALUE\nossl_ssl_get_peer_cert_chain(VALUE self)\n{\n    SSL *ssl;\n    STACK_OF(X509) *chain;\n    X509 *cert;\n    VALUE ary;\n    int i, num;\n\n    GetSSL(self, ssl);\n\n    chain = SSL_get_peer_cert_chain(ssl);\n    if(!chain) return Qnil;\n    num = sk_X509_num(chain);\n    ary = rb_ary_new2(num);\n    for (i = 0; i < num; i++){\n        cert = sk_X509_value(chain, i);\n        rb_ary_push(ary, ossl_x509_new(cert));\n    }\n\n    return ary;\n}\n\n/*\n * call-seq:\n *    ssl.ssl_version => String\n *\n * Returns a String representing the SSL/TLS version that was negotiated\n * for the connection, for example \"TLSv1.2\".\n */\nstatic VALUE\nossl_ssl_get_version(VALUE self)\n{\n    SSL *ssl;\n\n    GetSSL(self, ssl);\n\n    return rb_str_new2(SSL_get_version(ssl));\n}\n\n/*\n * call-seq:\n *    ssl.cipher -> nil or [name, version, bits, alg_bits]\n *\n * Returns the cipher suite actually used in the current session, or nil if\n * no session has been established.\n */\nstatic VALUE\nossl_ssl_get_cipher(VALUE self)\n{\n    SSL *ssl;\n    const SSL_CIPHER *cipher;\n\n    GetSSL(self, ssl);\n    cipher = SSL_get_current_cipher(ssl);\n    return cipher ? ossl_ssl_cipher_to_ary(cipher) : Qnil;\n}\n\n/*\n * call-seq:\n *    ssl.state => string\n *\n * A description of the current connection state. This is for diagnostic\n * purposes only.\n */\nstatic VALUE\nossl_ssl_get_state(VALUE self)\n{\n    SSL *ssl;\n    VALUE ret;\n\n    GetSSL(self, ssl);\n\n    ret = rb_str_new2(SSL_state_string(ssl));\n    if (ruby_verbose) {\n        rb_str_cat2(ret, \": \");\n        rb_str_cat2(ret, SSL_state_string_long(ssl));\n    }\n    return ret;\n}\n\n/*\n * call-seq:\n *    ssl.pending => Integer\n *\n * The number of bytes that are immediately available for reading.\n */\nstatic VALUE\nossl_ssl_pending(VALUE self)\n{\n    SSL *ssl;\n\n    GetSSL(self, ssl);\n\n    return INT2NUM(SSL_pending(ssl));\n}\n\n/*\n * call-seq:\n *    ssl.session_reused? -> true | false\n *\n * Returns +true+ if a reused session was negotiated during the handshake.\n */\nstatic VALUE\nossl_ssl_session_reused(VALUE self)\n{\n    SSL *ssl;\n\n    GetSSL(self, ssl);\n\n    return SSL_session_reused(ssl) ? Qtrue : Qfalse;\n}\n\n/*\n * call-seq:\n *    ssl.session = session -> session\n *\n * Sets the Session to be used when the connection is established.\n */\nstatic VALUE\nossl_ssl_set_session(VALUE self, VALUE arg1)\n{\n    SSL *ssl;\n    SSL_SESSION *sess;\n\n    GetSSL(self, ssl);\n    GetSSLSession(arg1, sess);\n\n    if (SSL_set_session(ssl, sess) != 1)\n        ossl_raise(eSSLError, \"SSL_set_session\");\n\n    return arg1;\n}\n\n/*\n * call-seq:\n *    ssl.hostname = hostname -> hostname\n *\n * Sets the server hostname used for SNI. This needs to be set before\n * SSLSocket#connect.\n */\nstatic VALUE\nossl_ssl_set_hostname(VALUE self, VALUE arg)\n{\n    SSL *ssl;\n    char *hostname = NULL;\n\n    GetSSL(self, ssl);\n\n    if (!NIL_P(arg))\n        hostname = StringValueCStr(arg);\n\n    if (!SSL_set_tlsext_host_name(ssl, hostname))\n        ossl_raise(eSSLError, NULL);\n\n    /* for SSLSocket#hostname */\n    rb_ivar_set(self, id_i_hostname, arg);\n\n    return arg;\n}\n\n/*\n * call-seq:\n *    ssl.verify_result => Integer\n *\n * Returns the result of the peer certificates verification.  See verify(1)\n * for error values and descriptions.\n *\n * If no peer certificate was presented X509_V_OK is returned.\n */\nstatic VALUE\nossl_ssl_get_verify_result(VALUE self)\n{\n    SSL *ssl;\n\n    GetSSL(self, ssl);\n\n    return LONG2NUM(SSL_get_verify_result(ssl));\n}\n\n/*\n * call-seq:\n *    ssl.finished_message => \"finished message\"\n *\n * Returns the last *Finished* message sent\n *\n */\nstatic VALUE\nossl_ssl_get_finished(VALUE self)\n{\n    SSL *ssl;\n    char sizer[1], *buf;\n    size_t len;\n\n    GetSSL(self, ssl);\n\n    len = SSL_get_finished(ssl, sizer, 0);\n    if (len == 0)\n        return Qnil;\n\n    buf = ALLOCA_N(char, len);\n    SSL_get_finished(ssl, buf, len);\n    return rb_str_new(buf, len);\n}\n\n/*\n * call-seq:\n *    ssl.peer_finished_message => \"peer finished message\"\n *\n * Returns the last *Finished* message received\n *\n */\nstatic VALUE\nossl_ssl_get_peer_finished(VALUE self)\n{\n    SSL *ssl;\n    char sizer[1], *buf;\n    size_t len;\n\n    GetSSL(self, ssl);\n\n    len = SSL_get_peer_finished(ssl, sizer, 0);\n    if (len == 0)\n        return Qnil;\n\n    buf = ALLOCA_N(char, len);\n    SSL_get_peer_finished(ssl, buf, len);\n    return rb_str_new(buf, len);\n}\n\n/*\n * call-seq:\n *    ssl.client_ca => [x509name, ...] or nil\n *\n * Returns the list of client CAs. Please note that in contrast to\n * SSLContext#client_ca= no array of X509::Certificate is returned but\n * X509::Name instances of the CA's subject distinguished name.\n *\n * In server mode, returns the list set by SSLContext#client_ca=.\n * In client mode, returns the list of client CAs sent from the server.\n */\nstatic VALUE\nossl_ssl_get_client_ca_list(VALUE self)\n{\n    SSL *ssl;\n    STACK_OF(X509_NAME) *ca;\n\n    GetSSL(self, ssl);\n\n    ca = SSL_get_client_CA_list(ssl);\n    if (!ca)\n        return Qnil;\n    return ossl_x509name_sk2ary(ca);\n}\n\n# ifdef OSSL_USE_NEXTPROTONEG\n/*\n * call-seq:\n *    ssl.npn_protocol => String | nil\n *\n * Returns the protocol string that was finally selected by the client\n * during the handshake.\n */\nstatic VALUE\nossl_ssl_npn_protocol(VALUE self)\n{\n    SSL *ssl;\n    const unsigned char *out;\n    unsigned int outlen;\n\n    GetSSL(self, ssl);\n\n    SSL_get0_next_proto_negotiated(ssl, &out, &outlen);\n    if (!outlen)\n        return Qnil;\n    else\n        return rb_str_new((const char *) out, outlen);\n}\n# endif\n\n/*\n * call-seq:\n *    ssl.alpn_protocol => String | nil\n *\n * Returns the ALPN protocol string that was finally selected by the server\n * during the handshake.\n */\nstatic VALUE\nossl_ssl_alpn_protocol(VALUE self)\n{\n    SSL *ssl;\n    const unsigned char *out;\n    unsigned int outlen;\n\n    GetSSL(self, ssl);\n\n    SSL_get0_alpn_selected(ssl, &out, &outlen);\n    if (!outlen)\n        return Qnil;\n    else\n        return rb_str_new((const char *) out, outlen);\n}\n\n/*\n * call-seq:\n *    session.export_keying_material(label, length) -> String\n *\n * Enables use of shared session key material in accordance with RFC 5705.\n */\nstatic VALUE\nossl_ssl_export_keying_material(int argc, VALUE *argv, VALUE self)\n{\n    SSL *ssl;\n    VALUE str;\n    VALUE label;\n    VALUE length;\n    VALUE context;\n    unsigned char *p;\n    size_t len;\n    int use_ctx = 0;\n    unsigned char *ctx = NULL;\n    size_t ctx_len = 0;\n    int ret;\n\n    rb_scan_args(argc, argv, \"21\", &label, &length, &context);\n    StringValue(label);\n\n    GetSSL(self, ssl);\n\n    len = (size_t)NUM2LONG(length);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (!NIL_P(context)) {\n        use_ctx = 1;\n        StringValue(context);\n        ctx = (unsigned char *)RSTRING_PTR(context);\n        ctx_len = RSTRING_LEN(context);\n    }\n    ret = SSL_export_keying_material(ssl, p, len, (char *)RSTRING_PTR(label),\n                                     RSTRING_LENINT(label), ctx, ctx_len, use_ctx);\n    if (ret == 0 || ret == -1) {\n        ossl_raise(eSSLError, \"SSL_export_keying_material\");\n    }\n    return str;\n}\n\n/*\n * call-seq:\n *    ssl.tmp_key => PKey or nil\n *\n * Returns the ephemeral key used in case of forward secrecy cipher.\n */\nstatic VALUE\nossl_ssl_tmp_key(VALUE self)\n{\n    SSL *ssl;\n    EVP_PKEY *key;\n\n    GetSSL(self, ssl);\n    if (!SSL_get_server_tmp_key(ssl, &key))\n        return Qnil;\n    return ossl_pkey_wrap(key);\n}\n\n#ifdef HAVE_SSL_GET0_PEER_SIGNATURE_NAME\n/*\n * call-seq:\n *    ssl.sigalg => String or nil\n *\n * Returns the signature algorithm name, the IANA name of the signature scheme\n * used by the local to sign the TLS handshake.\n */\nstatic VALUE\nossl_ssl_get_sigalg(VALUE self)\n{\n    SSL *ssl;\n    const char *name;\n\n    GetSSL(self, ssl);\n    if (!SSL_get0_signature_name(ssl, &name))\n        return Qnil;\n    return rb_str_new_cstr(name);\n}\n\n/*\n * call-seq:\n *    ssl.peer_sigalg => String or nil\n *\n * Returns the signature algorithm name, the IANA name of the signature scheme\n * used by the peer to sign the TLS handshake.\n */\nstatic VALUE\nossl_ssl_get_peer_sigalg(VALUE self)\n{\n    SSL *ssl;\n    const char *name;\n\n    GetSSL(self, ssl);\n    if (!SSL_get0_peer_signature_name(ssl, &name))\n        return Qnil;\n    return rb_str_new_cstr(name);\n}\n#endif\n\n#ifdef HAVE_SSL_GET0_GROUP_NAME\n/*\n * call-seq:\n *    ssl.group => String or nil\n *\n * Returns the name of the group that was used for the key agreement of the\n * current TLS session establishment.\n */\nstatic VALUE\nossl_ssl_get_group(VALUE self)\n{\n    SSL *ssl;\n    const char *name;\n\n    GetSSL(self, ssl);\n    if (!(name = SSL_get0_group_name(ssl)))\n        return Qnil;\n    return rb_str_new_cstr(name);\n}\n#endif\n\n#endif /* !defined(OPENSSL_NO_SOCK) */\n\nvoid\nInit_ossl_ssl(void)\n{\n#if 0\n    rb_mWaitReadable = rb_define_module_under(rb_cIO, \"WaitReadable\");\n    rb_mWaitWritable = rb_define_module_under(rb_cIO, \"WaitWritable\");\n#endif\n\n#ifndef OPENSSL_NO_SOCK\n    id_call = rb_intern_const(\"call\");\n    ID_callback_state = rb_intern_const(\"callback_state\");\n\n    ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0, (void *)\"ossl_ssl_ex_ptr_idx\", 0, 0, 0);\n    if (ossl_ssl_ex_ptr_idx < 0)\n        ossl_raise(rb_eRuntimeError, \"SSL_get_ex_new_index\");\n    ossl_sslctx_ex_ptr_idx = SSL_CTX_get_ex_new_index(0, (void *)\"ossl_sslctx_ex_ptr_idx\", 0, 0, 0);\n    if (ossl_sslctx_ex_ptr_idx < 0)\n        ossl_raise(rb_eRuntimeError, \"SSL_CTX_get_ex_new_index\");\n\n    /* Document-module: OpenSSL::SSL\n     *\n     * Use SSLContext to set up the parameters for a TLS (former SSL)\n     * connection. Both client and server TLS connections are supported,\n     * SSLSocket and SSLServer may be used in conjunction with an instance\n     * of SSLContext to set up connections.\n     */\n    mSSL = rb_define_module_under(mOSSL, \"SSL\");\n\n    /* Document-class: OpenSSL::SSL::SSLError\n     *\n     * Generic error class raised by SSLSocket and SSLContext.\n     */\n    eSSLError = rb_define_class_under(mSSL, \"SSLError\", eOSSLError);\n    eSSLErrorWaitReadable = rb_define_class_under(mSSL, \"SSLErrorWaitReadable\", eSSLError);\n    rb_include_module(eSSLErrorWaitReadable, rb_mWaitReadable);\n    eSSLErrorWaitWritable = rb_define_class_under(mSSL, \"SSLErrorWaitWritable\", eSSLError);\n    rb_include_module(eSSLErrorWaitWritable, rb_mWaitWritable);\n\n    Init_ossl_ssl_session();\n\n    /* Document-class: OpenSSL::SSL::SSLContext\n     *\n     * An SSLContext is used to set various options regarding certificates,\n     * algorithms, verification, session caching, etc.  The SSLContext is\n     * used to create an SSLSocket.\n     *\n     * All attributes must be set before creating an SSLSocket as the\n     * SSLContext will be frozen afterward.\n     */\n    cSSLContext = rb_define_class_under(mSSL, \"SSLContext\", rb_cObject);\n    rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc);\n    rb_undef_method(cSSLContext, \"initialize_copy\");\n\n    /*\n     * Context certificate\n     *\n     * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.\n     * It is recommended to use #add_certificate instead.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"cert\"), 1, 1, Qfalse);\n\n    /*\n     * Context private key\n     *\n     * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.\n     * It is recommended to use #add_certificate instead.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"key\"), 1, 1, Qfalse);\n\n    /*\n     * A certificate or Array of certificates that will be sent to the client.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"client_ca\"), 1, 1, Qfalse);\n\n    /*\n     * The path to a file containing a PEM-format CA certificate\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"ca_file\"), 1, 1, Qfalse);\n\n    /*\n     * The path to a directory containing CA certificates in PEM format.\n     *\n     * Files are looked up by subject's X509 name's hash value.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"ca_path\"), 1, 1, Qfalse);\n\n    /*\n     * Maximum session lifetime in seconds.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"timeout\"), 1, 1, Qfalse);\n\n    /*\n     * Session verification mode.\n     *\n     * Valid modes are VERIFY_NONE, VERIFY_PEER, VERIFY_CLIENT_ONCE,\n     * VERIFY_FAIL_IF_NO_PEER_CERT and defined on OpenSSL::SSL\n     *\n     * The default mode is VERIFY_NONE, which does not perform any verification\n     * at all.\n     *\n     * See SSL_CTX_set_verify(3) for details.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"verify_mode\"), 1, 1, Qfalse);\n\n    /*\n     * Number of CA certificates to walk when verifying a certificate chain.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"verify_depth\"), 1, 1, Qfalse);\n\n    /*\n     * A callback for additional certificate verification.  The callback is\n     * invoked for each certificate in the chain.\n     *\n     * The callback is invoked with two values.  _preverify_ok_ indicates\n     * indicates if the verification was passed (+true+) or not (+false+).\n     * _store_context_ is an OpenSSL::X509::StoreContext containing the\n     * context used for certificate verification.\n     *\n     * If the callback returns +false+, the chain verification is immediately\n     * stopped and a bad_certificate alert is then sent.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"verify_callback\"), 1, 1, Qfalse);\n\n    /*\n     * Whether to check the server certificate is valid for the hostname.\n     *\n     * In order to make this work, verify_mode must be set to VERIFY_PEER and\n     * the server hostname must be given by OpenSSL::SSL::SSLSocket#hostname=.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"verify_hostname\"), 1, 1, Qfalse);\n\n    /*\n     * An OpenSSL::X509::Store used for certificate verification.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"cert_store\"), 1, 1, Qfalse);\n\n    /*\n     * An Array of extra X509 certificates to be added to the certificate\n     * chain.\n     *\n     * The _cert_, _key_, and _extra_chain_cert_ attributes are deprecated.\n     * It is recommended to use #add_certificate instead.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"extra_chain_cert\"), 1, 1, Qfalse);\n\n    /*\n     * A callback invoked when a client certificate is requested by a server\n     * and no certificate has been set.\n     *\n     * The callback is invoked with a Session and must return an Array\n     * containing an OpenSSL::X509::Certificate and an OpenSSL::PKey.  If any\n     * other value is returned the handshake is suspended.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"client_cert_cb\"), 1, 1, Qfalse);\n\n#ifndef OPENSSL_NO_DH\n    /*\n     * A callback invoked when DH parameters are required for ephemeral DH key\n     * exchange.\n     *\n     * The callback is invoked with the SSLSocket, a\n     * flag indicating the use of an export cipher and the keylength\n     * required.\n     *\n     * The callback must return an OpenSSL::PKey::DH instance of the correct\n     * key length.\n     *\n     * <b>Deprecated in version 3.0.</b> Use #tmp_dh= instead.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"tmp_dh_callback\"), 1, 1, Qfalse);\n#endif\n\n    /*\n     * Sets the context in which a session can be reused.  This allows\n     * sessions for multiple applications to be distinguished, for example, by\n     * name.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"session_id_context\"), 1, 1, Qfalse);\n\n    /*\n     * A callback invoked on a server when a session is proposed by the client\n     * but the session could not be found in the server's internal cache.\n     *\n     * The callback is invoked with the SSLSocket and session id.  The\n     * callback may return a Session from an external cache.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"session_get_cb\"), 1, 1, Qfalse);\n\n    /*\n     * A callback invoked when a new session was negotiated.\n     *\n     * The callback is invoked with an SSLSocket.  If +false+ is returned the\n     * session will be removed from the internal cache.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"session_new_cb\"), 1, 1, Qfalse);\n\n    /*\n     * A callback invoked when a session is removed from the internal cache.\n     *\n     * The callback is invoked with an SSLContext and a Session.\n     *\n     * IMPORTANT NOTE: It is currently not possible to use this safely in a\n     * multi-threaded application. The callback is called inside a global lock\n     * and it can randomly cause deadlock on Ruby thread switching.\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"session_remove_cb\"), 1, 1, Qfalse);\n\n    /*\n     * A callback invoked whenever a new handshake is initiated on an\n     * established connection. May be used to disable renegotiation entirely.\n     *\n     * The callback is invoked with the active SSLSocket. The callback's\n     * return value is ignored. A normal return indicates \"approval\" of the\n     * renegotiation and will continue the process. To forbid renegotiation\n     * and to cancel the process, raise an exception within the callback.\n     *\n     * === Disable client renegotiation\n     *\n     * When running a server, it is often desirable to disable client\n     * renegotiation entirely. You may use a callback as follows to implement\n     * this feature:\n     *\n     *   ctx.renegotiation_cb = lambda do |ssl|\n     *     raise RuntimeError, \"Client renegotiation disabled\"\n     *   end\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"renegotiation_cb\"), 1, 1, Qfalse);\n#ifdef OSSL_USE_NEXTPROTONEG\n    /*\n     * An Enumerable of Strings. Each String represents a protocol to be\n     * advertised as the list of supported protocols for Next Protocol\n     * Negotiation. Supported in OpenSSL 1.0.1 and higher. Has no effect\n     * on the client side. If not set explicitly, the NPN extension will\n     * not be sent by the server in the handshake.\n     *\n     * === Example\n     *\n     *   ctx.npn_protocols = [\"http/1.1\", \"spdy/2\"]\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"npn_protocols\"), 1, 1, Qfalse);\n    /*\n     * A callback invoked on the client side when the client needs to select\n     * a protocol from the list sent by the server. Supported in OpenSSL 1.0.1\n     * and higher. The client MUST select a protocol of those advertised by\n     * the server. If none is acceptable, raising an error in the callback\n     * will cause the handshake to fail. Not setting this callback explicitly\n     * means not supporting the NPN extension on the client - any protocols\n     * advertised by the server will be ignored.\n     *\n     * === Example\n     *\n     *   ctx.npn_select_cb = lambda do |protocols|\n     *     # inspect the protocols and select one\n     *     protocols.first\n     *   end\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"npn_select_cb\"), 1, 1, Qfalse);\n#endif\n\n    /*\n     * An Enumerable of Strings. Each String represents a protocol to be\n     * advertised as the list of supported protocols for Application-Layer\n     * Protocol Negotiation. Supported in OpenSSL 1.0.2 and higher. Has no\n     * effect on the server side. If not set explicitly, the ALPN extension will\n     * not be included in the handshake.\n     *\n     * === Example\n     *\n     *   ctx.alpn_protocols = [\"http/1.1\", \"spdy/2\", \"h2\"]\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"alpn_protocols\"), 1, 1, Qfalse);\n    /*\n     * A callback invoked on the server side when the server needs to select\n     * a protocol from the list sent by the client. Supported in OpenSSL 1.0.2\n     * and higher. The callback must return a protocol of those advertised by\n     * the client. If none is acceptable, raising an error in the callback\n     * will cause the handshake to fail. Not setting this callback explicitly\n     * means not supporting the ALPN extension on the server - any protocols\n     * advertised by the client will be ignored.\n     *\n     * === Example\n     *\n     *   ctx.alpn_select_cb = lambda do |protocols|\n     *     # inspect the protocols and select one\n     *     protocols.first\n     *   end\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"alpn_select_cb\"), 1, 1, Qfalse);\n\n    /*\n     * A callback invoked when TLS key material is generated or received, in\n     * order to allow applications to store this keying material for debugging\n     * purposes.\n     *\n     * The callback is invoked with an SSLSocket and a string containing the\n     * key material in the format used by NSS for its SSLKEYLOGFILE debugging\n     * output.\n     *\n     * It is only compatible with OpenSSL >= 1.1.1. Even if LibreSSL implements\n     * SSL_CTX_set_keylog_callback() from v3.4.2, it does nothing (see\n     * https://github.com/libressl-portable/openbsd/commit/648d39f0f035835d0653342d139883b9661e9cb6).\n     *\n     * === Example\n     *\n     *   context.keylog_cb = proc do |_sock, line|\n     *     File.open('ssl_keylog_file', \"a\") do |f|\n     *       f.write(\"#{line}\\n\")\n     *     end\n     *   end\n     */\n    rb_attr(cSSLContext, rb_intern_const(\"keylog_cb\"), 1, 1, Qfalse);\n\n    rb_define_alias(cSSLContext, \"ssl_timeout\", \"timeout\");\n    rb_define_alias(cSSLContext, \"ssl_timeout=\", \"timeout=\");\n    rb_define_method(cSSLContext, \"min_version=\", ossl_sslctx_set_min_version, 1);\n    rb_define_method(cSSLContext, \"max_version=\", ossl_sslctx_set_max_version, 1);\n    rb_define_method(cSSLContext, \"ciphers\",     ossl_sslctx_get_ciphers, 0);\n    rb_define_method(cSSLContext, \"ciphers=\",    ossl_sslctx_set_ciphers, 1);\n    rb_define_method(cSSLContext, \"ciphersuites=\", ossl_sslctx_set_ciphersuites, 1);\n#ifdef HAVE_SSL_CTX_SET1_SIGALGS_LIST // Not in LibreSSL yet\n    rb_define_method(cSSLContext, \"sigalgs=\", ossl_sslctx_set_sigalgs, 1);\n#endif\n#ifdef HAVE_SSL_CTX_SET1_CLIENT_SIGALGS_LIST // Not in LibreSSL or AWS-LC yet\n    rb_define_method(cSSLContext, \"client_sigalgs=\", ossl_sslctx_set_client_sigalgs, 1);\n#endif\n#ifndef OPENSSL_NO_DH\n    rb_define_method(cSSLContext, \"tmp_dh=\", ossl_sslctx_set_tmp_dh, 1);\n#endif\n    rb_define_method(cSSLContext, \"groups=\", ossl_sslctx_set_groups, 1);\n    rb_define_alias(cSSLContext, \"ecdh_curves=\", \"groups=\");\n    rb_define_method(cSSLContext, \"security_level\", ossl_sslctx_get_security_level, 0);\n    rb_define_method(cSSLContext, \"security_level=\", ossl_sslctx_set_security_level, 1);\n#ifdef SSL_MODE_SEND_FALLBACK_SCSV\n    rb_define_method(cSSLContext, \"enable_fallback_scsv\", ossl_sslctx_enable_fallback_scsv, 0);\n#endif\n    rb_define_method(cSSLContext, \"add_certificate\", ossl_sslctx_add_certificate, -1);\n\n    rb_define_method(cSSLContext, \"setup\", ossl_sslctx_setup, 0);\n    rb_define_alias(cSSLContext, \"freeze\", \"setup\");\n\n    /*\n     * No session caching for client or server\n     */\n    rb_define_const(cSSLContext, \"SESSION_CACHE_OFF\", LONG2NUM(SSL_SESS_CACHE_OFF));\n\n    /*\n     * Client sessions are added to the session cache\n     */\n    rb_define_const(cSSLContext, \"SESSION_CACHE_CLIENT\", LONG2NUM(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */\n\n    /*\n     * Server sessions are added to the session cache\n     */\n    rb_define_const(cSSLContext, \"SESSION_CACHE_SERVER\", LONG2NUM(SSL_SESS_CACHE_SERVER));\n\n    /*\n     * Both client and server sessions are added to the session cache\n     */\n    rb_define_const(cSSLContext, \"SESSION_CACHE_BOTH\", LONG2NUM(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */\n\n    /*\n     * Normally the session cache is checked for expired sessions every 255\n     * connections.  Since this may lead to a delay that cannot be controlled,\n     * the automatic flushing may be disabled and #flush_sessions can be\n     * called explicitly.\n     */\n    rb_define_const(cSSLContext, \"SESSION_CACHE_NO_AUTO_CLEAR\", LONG2NUM(SSL_SESS_CACHE_NO_AUTO_CLEAR));\n\n    /*\n     * Always perform external lookups of sessions even if they are in the\n     * internal cache.\n     *\n     * This flag has no effect on clients\n     */\n    rb_define_const(cSSLContext, \"SESSION_CACHE_NO_INTERNAL_LOOKUP\", LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP));\n\n    /*\n     * Never automatically store sessions in the internal store.\n     */\n    rb_define_const(cSSLContext, \"SESSION_CACHE_NO_INTERNAL_STORE\", LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL_STORE));\n\n    /*\n     * Enables both SESSION_CACHE_NO_INTERNAL_LOOKUP and\n     * SESSION_CACHE_NO_INTERNAL_STORE.\n     */\n    rb_define_const(cSSLContext, \"SESSION_CACHE_NO_INTERNAL\", LONG2NUM(SSL_SESS_CACHE_NO_INTERNAL));\n\n    rb_define_method(cSSLContext, \"session_add\",     ossl_sslctx_session_add, 1);\n    rb_define_method(cSSLContext, \"session_remove\",     ossl_sslctx_session_remove, 1);\n    rb_define_method(cSSLContext, \"session_cache_mode\",     ossl_sslctx_get_session_cache_mode, 0);\n    rb_define_method(cSSLContext, \"session_cache_mode=\",     ossl_sslctx_set_session_cache_mode, 1);\n    rb_define_method(cSSLContext, \"session_cache_size\",     ossl_sslctx_get_session_cache_size, 0);\n    rb_define_method(cSSLContext, \"session_cache_size=\",     ossl_sslctx_set_session_cache_size, 1);\n    rb_define_method(cSSLContext, \"session_cache_stats\",     ossl_sslctx_get_session_cache_stats, 0);\n    rb_define_method(cSSLContext, \"flush_sessions\",     ossl_sslctx_flush_sessions, -1);\n    rb_define_method(cSSLContext, \"options\",     ossl_sslctx_get_options, 0);\n    rb_define_method(cSSLContext, \"options=\",     ossl_sslctx_set_options, 1);\n\n    /*\n     * Document-class: OpenSSL::SSL::SSLSocket\n     */\n    cSSLSocket = rb_define_class_under(mSSL, \"SSLSocket\", rb_cObject);\n    rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc);\n    rb_define_method(cSSLSocket, \"initialize\", ossl_ssl_initialize, -1);\n    rb_undef_method(cSSLSocket, \"initialize_copy\");\n    rb_define_method(cSSLSocket, \"connect\",    ossl_ssl_connect, 0);\n    rb_define_method(cSSLSocket, \"connect_nonblock\",    ossl_ssl_connect_nonblock, -1);\n    rb_define_method(cSSLSocket, \"accept\",     ossl_ssl_accept, 0);\n    rb_define_method(cSSLSocket, \"accept_nonblock\", ossl_ssl_accept_nonblock, -1);\n    rb_define_method(cSSLSocket, \"sysread\",    ossl_ssl_read, -1);\n    rb_define_private_method(cSSLSocket, \"sysread_nonblock\",    ossl_ssl_read_nonblock, -1);\n    rb_define_method(cSSLSocket, \"syswrite\",   ossl_ssl_write, 1);\n    rb_define_private_method(cSSLSocket, \"syswrite_nonblock\",    ossl_ssl_write_nonblock, -1);\n    rb_define_private_method(cSSLSocket, \"stop\",   ossl_ssl_stop, 0);\n    rb_define_method(cSSLSocket, \"cert\",       ossl_ssl_get_cert, 0);\n    rb_define_method(cSSLSocket, \"peer_cert\",  ossl_ssl_get_peer_cert, 0);\n    rb_define_method(cSSLSocket, \"peer_cert_chain\", ossl_ssl_get_peer_cert_chain, 0);\n    rb_define_method(cSSLSocket, \"ssl_version\",    ossl_ssl_get_version, 0);\n    rb_define_method(cSSLSocket, \"cipher\",     ossl_ssl_get_cipher, 0);\n    rb_define_method(cSSLSocket, \"state\",      ossl_ssl_get_state, 0);\n    rb_define_method(cSSLSocket, \"pending\",    ossl_ssl_pending, 0);\n    rb_define_method(cSSLSocket, \"session_reused?\",    ossl_ssl_session_reused, 0);\n    /* implementation of OpenSSL::SSL::SSLSocket#session is in lib/openssl/ssl.rb */\n    rb_define_method(cSSLSocket, \"session=\",    ossl_ssl_set_session, 1);\n    rb_define_method(cSSLSocket, \"verify_result\", ossl_ssl_get_verify_result, 0);\n    rb_define_method(cSSLSocket, \"client_ca\", ossl_ssl_get_client_ca_list, 0);\n    /* #hostname is defined in lib/openssl/ssl.rb */\n    rb_define_method(cSSLSocket, \"hostname=\", ossl_ssl_set_hostname, 1);\n    rb_define_method(cSSLSocket, \"finished_message\", ossl_ssl_get_finished, 0);\n    rb_define_method(cSSLSocket, \"peer_finished_message\", ossl_ssl_get_peer_finished, 0);\n    rb_define_method(cSSLSocket, \"tmp_key\", ossl_ssl_tmp_key, 0);\n    rb_define_method(cSSLSocket, \"alpn_protocol\", ossl_ssl_alpn_protocol, 0);\n    rb_define_method(cSSLSocket, \"export_keying_material\", ossl_ssl_export_keying_material, -1);\n# ifdef OSSL_USE_NEXTPROTONEG\n    rb_define_method(cSSLSocket, \"npn_protocol\", ossl_ssl_npn_protocol, 0);\n# endif\n#ifdef HAVE_SSL_GET0_PEER_SIGNATURE_NAME\n    rb_define_method(cSSLSocket, \"sigalg\", ossl_ssl_get_sigalg, 0);\n    rb_define_method(cSSLSocket, \"peer_sigalg\", ossl_ssl_get_peer_sigalg, 0);\n#endif\n#ifdef HAVE_SSL_GET0_GROUP_NAME\n    rb_define_method(cSSLSocket, \"group\", ossl_ssl_get_group, 0);\n#endif\n\n    rb_define_const(mSSL, \"VERIFY_NONE\", INT2NUM(SSL_VERIFY_NONE));\n    rb_define_const(mSSL, \"VERIFY_PEER\", INT2NUM(SSL_VERIFY_PEER));\n    rb_define_const(mSSL, \"VERIFY_FAIL_IF_NO_PEER_CERT\", INT2NUM(SSL_VERIFY_FAIL_IF_NO_PEER_CERT));\n    rb_define_const(mSSL, \"VERIFY_CLIENT_ONCE\", INT2NUM(SSL_VERIFY_CLIENT_ONCE));\n\n    rb_define_const(mSSL, \"OP_ALL\", ULONG2NUM(SSL_OP_ALL));\n#ifdef SSL_OP_CLEANSE_PLAINTEXT /* OpenSSL 3.0 */\n    rb_define_const(mSSL, \"OP_CLEANSE_PLAINTEXT\", ULONG2NUM(SSL_OP_CLEANSE_PLAINTEXT));\n#endif\n    rb_define_const(mSSL, \"OP_LEGACY_SERVER_CONNECT\", ULONG2NUM(SSL_OP_LEGACY_SERVER_CONNECT));\n#ifdef SSL_OP_ENABLE_KTLS /* OpenSSL 3.0 */\n    rb_define_const(mSSL, \"OP_ENABLE_KTLS\", ULONG2NUM(SSL_OP_ENABLE_KTLS));\n#endif\n    rb_define_const(mSSL, \"OP_TLSEXT_PADDING\", ULONG2NUM(SSL_OP_TLSEXT_PADDING));\n    rb_define_const(mSSL, \"OP_SAFARI_ECDHE_ECDSA_BUG\", ULONG2NUM(SSL_OP_SAFARI_ECDHE_ECDSA_BUG));\n#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF /* OpenSSL 3.0 */\n    rb_define_const(mSSL, \"OP_IGNORE_UNEXPECTED_EOF\", ULONG2NUM(SSL_OP_IGNORE_UNEXPECTED_EOF));\n#endif\n#ifdef SSL_OP_ALLOW_CLIENT_RENEGOTIATION /* OpenSSL 3.0 */\n    rb_define_const(mSSL, \"OP_ALLOW_CLIENT_RENEGOTIATION\", ULONG2NUM(SSL_OP_ALLOW_CLIENT_RENEGOTIATION));\n#endif\n#ifdef SSL_OP_DISABLE_TLSEXT_CA_NAMES /* OpenSSL 3.0 */\n    rb_define_const(mSSL, \"OP_DISABLE_TLSEXT_CA_NAMES\", ULONG2NUM(SSL_OP_DISABLE_TLSEXT_CA_NAMES));\n#endif\n#ifdef SSL_OP_ALLOW_NO_DHE_KEX /* OpenSSL 1.1.1, missing in LibreSSL */\n    rb_define_const(mSSL, \"OP_ALLOW_NO_DHE_KEX\", ULONG2NUM(SSL_OP_ALLOW_NO_DHE_KEX));\n#endif\n    rb_define_const(mSSL, \"OP_DONT_INSERT_EMPTY_FRAGMENTS\", ULONG2NUM(SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS));\n    rb_define_const(mSSL, \"OP_NO_TICKET\", ULONG2NUM(SSL_OP_NO_TICKET));\n    rb_define_const(mSSL, \"OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION\", ULONG2NUM(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION));\n    rb_define_const(mSSL, \"OP_NO_COMPRESSION\", ULONG2NUM(SSL_OP_NO_COMPRESSION));\n    rb_define_const(mSSL, \"OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION\", ULONG2NUM(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION));\n#ifdef SSL_OP_NO_ENCRYPT_THEN_MAC /* OpenSSL 1.1.1, missing in LibreSSL */\n    rb_define_const(mSSL, \"OP_NO_ENCRYPT_THEN_MAC\", ULONG2NUM(SSL_OP_NO_ENCRYPT_THEN_MAC));\n#endif\n#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT /* OpenSSL 1.1.1, missing in LibreSSL */\n    rb_define_const(mSSL, \"OP_ENABLE_MIDDLEBOX_COMPAT\", ULONG2NUM(SSL_OP_ENABLE_MIDDLEBOX_COMPAT));\n#endif\n#ifdef SSL_OP_PRIORITIZE_CHACHA /* OpenSSL 1.1.1, missing in LibreSSL */\n    rb_define_const(mSSL, \"OP_PRIORITIZE_CHACHA\", ULONG2NUM(SSL_OP_PRIORITIZE_CHACHA));\n#endif\n#ifdef SSL_OP_NO_ANTI_REPLAY /* OpenSSL 1.1.1, missing in LibreSSL */\n    rb_define_const(mSSL, \"OP_NO_ANTI_REPLAY\", ULONG2NUM(SSL_OP_NO_ANTI_REPLAY));\n#endif\n    rb_define_const(mSSL, \"OP_NO_SSLv3\", ULONG2NUM(SSL_OP_NO_SSLv3));\n    rb_define_const(mSSL, \"OP_NO_TLSv1\", ULONG2NUM(SSL_OP_NO_TLSv1));\n    rb_define_const(mSSL, \"OP_NO_TLSv1_1\", ULONG2NUM(SSL_OP_NO_TLSv1_1));\n    rb_define_const(mSSL, \"OP_NO_TLSv1_2\", ULONG2NUM(SSL_OP_NO_TLSv1_2));\n    rb_define_const(mSSL, \"OP_NO_TLSv1_3\", ULONG2NUM(SSL_OP_NO_TLSv1_3));\n    rb_define_const(mSSL, \"OP_CIPHER_SERVER_PREFERENCE\", ULONG2NUM(SSL_OP_CIPHER_SERVER_PREFERENCE));\n    rb_define_const(mSSL, \"OP_TLS_ROLLBACK_BUG\", ULONG2NUM(SSL_OP_TLS_ROLLBACK_BUG));\n#ifdef SSL_OP_NO_RENEGOTIATION /* OpenSSL 1.1.1, missing in LibreSSL */\n    rb_define_const(mSSL, \"OP_NO_RENEGOTIATION\", ULONG2NUM(SSL_OP_NO_RENEGOTIATION));\n#endif\n    rb_define_const(mSSL, \"OP_CRYPTOPRO_TLSEXT_BUG\", ULONG2NUM(SSL_OP_CRYPTOPRO_TLSEXT_BUG));\n\n    /* SSL_OP_* flags for DTLS */\n#if 0\n    rb_define_const(mSSL, \"OP_NO_QUERY_MTU\", ULONG2NUM(SSL_OP_NO_QUERY_MTU));\n    rb_define_const(mSSL, \"OP_COOKIE_EXCHANGE\", ULONG2NUM(SSL_OP_COOKIE_EXCHANGE));\n    rb_define_const(mSSL, \"OP_CISCO_ANYCONNECT\", ULONG2NUM(SSL_OP_CISCO_ANYCONNECT));\n#endif\n\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_MICROSOFT_SESS_ID_BUG\", ULONG2NUM(SSL_OP_MICROSOFT_SESS_ID_BUG));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_NETSCAPE_CHALLENGE_BUG\", ULONG2NUM(SSL_OP_NETSCAPE_CHALLENGE_BUG));\n    /* Deprecated in OpenSSL 0.9.8q and 1.0.0c. */\n    rb_define_const(mSSL, \"OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG\", ULONG2NUM(SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG));\n    /* Deprecated in OpenSSL 1.0.1h and 1.0.2. */\n    rb_define_const(mSSL, \"OP_SSLREF2_REUSE_CERT_TYPE_BUG\", ULONG2NUM(SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_MICROSOFT_BIG_SSLV3_BUFFER\", ULONG2NUM(SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER));\n    /* Deprecated in OpenSSL 0.9.7h and 0.9.8b. */\n    rb_define_const(mSSL, \"OP_MSIE_SSLV2_RSA_PADDING\", ULONG2NUM(SSL_OP_MSIE_SSLV2_RSA_PADDING));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_SSLEAY_080_CLIENT_DH_BUG\", ULONG2NUM(SSL_OP_SSLEAY_080_CLIENT_DH_BUG));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_TLS_D5_BUG\", ULONG2NUM(SSL_OP_TLS_D5_BUG));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_TLS_BLOCK_PADDING_BUG\", ULONG2NUM(SSL_OP_TLS_BLOCK_PADDING_BUG));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_SINGLE_ECDH_USE\", ULONG2NUM(SSL_OP_SINGLE_ECDH_USE));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_SINGLE_DH_USE\", ULONG2NUM(SSL_OP_SINGLE_DH_USE));\n    /* Deprecated in OpenSSL 1.0.1k and 1.0.2. */\n    rb_define_const(mSSL, \"OP_EPHEMERAL_RSA\", ULONG2NUM(SSL_OP_EPHEMERAL_RSA));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_NO_SSLv2\", ULONG2NUM(SSL_OP_NO_SSLv2));\n    /* Deprecated in OpenSSL 1.0.1. */\n    rb_define_const(mSSL, \"OP_PKCS1_CHECK_1\", ULONG2NUM(SSL_OP_PKCS1_CHECK_1));\n    /* Deprecated in OpenSSL 1.0.1. */\n    rb_define_const(mSSL, \"OP_PKCS1_CHECK_2\", ULONG2NUM(SSL_OP_PKCS1_CHECK_2));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_NETSCAPE_CA_DN_BUG\", ULONG2NUM(SSL_OP_NETSCAPE_CA_DN_BUG));\n    /* Deprecated in OpenSSL 1.1.0. */\n    rb_define_const(mSSL, \"OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG\", ULONG2NUM(SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG));\n\n\n    /*\n     * SSL/TLS version constants. Used by SSLContext#min_version= and\n     * #max_version=\n     */\n    /* SSL 2.0 */\n    rb_define_const(mSSL, \"SSL2_VERSION\", INT2NUM(SSL2_VERSION));\n    /* SSL 3.0 */\n    rb_define_const(mSSL, \"SSL3_VERSION\", INT2NUM(SSL3_VERSION));\n    /* TLS 1.0 */\n    rb_define_const(mSSL, \"TLS1_VERSION\", INT2NUM(TLS1_VERSION));\n    /* TLS 1.1 */\n    rb_define_const(mSSL, \"TLS1_1_VERSION\", INT2NUM(TLS1_1_VERSION));\n    /* TLS 1.2 */\n    rb_define_const(mSSL, \"TLS1_2_VERSION\", INT2NUM(TLS1_2_VERSION));\n    /* TLS 1.3 */\n    rb_define_const(mSSL, \"TLS1_3_VERSION\", INT2NUM(TLS1_3_VERSION));\n\n\n    sym_exception = ID2SYM(rb_intern_const(\"exception\"));\n    sym_wait_readable = ID2SYM(rb_intern_const(\"wait_readable\"));\n    sym_wait_writable = ID2SYM(rb_intern_const(\"wait_writable\"));\n\n    id_npn_protocols_encoded = rb_intern_const(\"npn_protocols_encoded\");\n    id_each = rb_intern_const(\"each\");\n\n#define DefIVarID(name) do \\\n    id_i_##name = rb_intern_const(\"@\"#name); while (0)\n\n    DefIVarID(cert_store);\n    DefIVarID(ca_file);\n    DefIVarID(ca_path);\n    DefIVarID(verify_mode);\n    DefIVarID(verify_depth);\n    DefIVarID(verify_callback);\n    DefIVarID(client_ca);\n    DefIVarID(renegotiation_cb);\n    DefIVarID(cert);\n    DefIVarID(key);\n    DefIVarID(extra_chain_cert);\n    DefIVarID(client_cert_cb);\n    DefIVarID(timeout);\n    DefIVarID(session_id_context);\n    DefIVarID(session_get_cb);\n    DefIVarID(session_new_cb);\n    DefIVarID(session_remove_cb);\n    DefIVarID(npn_select_cb);\n    DefIVarID(npn_protocols);\n    DefIVarID(alpn_protocols);\n    DefIVarID(alpn_select_cb);\n    DefIVarID(servername_cb);\n    DefIVarID(verify_hostname);\n    DefIVarID(keylog_cb);\n    DefIVarID(tmp_dh_callback);\n\n    DefIVarID(io);\n    DefIVarID(context);\n    DefIVarID(hostname);\n    DefIVarID(sync_close);\n#endif /* !defined(OPENSSL_NO_SOCK) */\n}\n"
  },
  {
    "path": "ext/openssl/ossl_ssl.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_SSL_H_)\n#define _OSSL_SSL_H_\n\n#define GetSSL(obj, ssl) do { \\\n    TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \\\n    if (!(ssl)) { \\\n        ossl_raise(rb_eRuntimeError, \"SSL is not initialized\"); \\\n    } \\\n} while (0)\n\n#define GetSSLSession(obj, sess) do { \\\n    TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \\\n    if (!(sess)) { \\\n        ossl_raise(rb_eRuntimeError, \"SSL Session wasn't initialized.\"); \\\n    } \\\n} while (0)\n\nextern const rb_data_type_t ossl_ssl_type;\nextern const rb_data_type_t ossl_ssl_session_type;\nextern VALUE mSSL;\nextern VALUE cSSLSocket;\nextern VALUE cSSLSession;\n\nvoid Init_ossl_ssl(void);\nvoid Init_ossl_ssl_session(void);\n\n#endif /* _OSSL_SSL_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_ssl_session.c",
    "content": "/*\n *  Copyright (C) 2004-2007 Technorama Ltd. <oss-ruby@technorama.net>\n */\n\n#include \"ossl.h\"\n\n#ifndef OPENSSL_NO_SOCK\nVALUE cSSLSession;\nstatic VALUE eSSLSession;\n\nstatic void\nossl_ssl_session_free(void *ptr)\n{\n    SSL_SESSION_free(ptr);\n}\n\nconst rb_data_type_t ossl_ssl_session_type = {\n    \"OpenSSL/SSL/Session\",\n    {\n        0, ossl_ssl_session_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE ossl_ssl_session_alloc(VALUE klass)\n{\n    return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL);\n}\n\n/*\n * call-seq:\n *   Session.new(ssl_socket) -> Session\n *   Session.new(string) -> Session\n *\n * Creates a new Session object from an instance of SSLSocket or DER/PEM encoded\n * String.\n */\nstatic VALUE\nossl_ssl_session_initialize(VALUE self, VALUE arg1)\n{\n    SSL_SESSION *ctx;\n\n    if (RTYPEDDATA_DATA(self))\n        ossl_raise(eSSLSession, \"SSL Session already initialized\");\n\n    if (rb_obj_is_instance_of(arg1, cSSLSocket)) {\n        SSL *ssl;\n\n        GetSSL(arg1, ssl);\n\n        if ((ctx = SSL_get1_session(ssl)) == NULL)\n            ossl_raise(eSSLSession, \"no session available\");\n    }\n    else {\n        BIO *in = ossl_obj2bio(&arg1);\n\n        ctx = d2i_SSL_SESSION_bio(in, NULL);\n        if (!ctx) {\n            OSSL_BIO_reset(in);\n            ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);\n        }\n        BIO_free(in);\n        if (!ctx)\n            ossl_raise(rb_eArgError, \"unknown type\");\n    }\n\n    RTYPEDDATA_DATA(self) = ctx;\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_ssl_session_initialize_copy(VALUE self, VALUE other)\n{\n    SSL_SESSION *sess, *sess_other, *sess_new;\n\n    rb_check_frozen(self);\n    sess = RTYPEDDATA_DATA(self); /* XXX */\n    GetSSLSession(other, sess_other);\n\n    sess_new = ASN1_dup((i2d_of_void *)i2d_SSL_SESSION, (d2i_of_void *)d2i_SSL_SESSION,\n                        (char *)sess_other);\n    if (!sess_new)\n        ossl_raise(eSSLSession, \"ASN1_dup\");\n\n    RTYPEDDATA_DATA(self) = sess_new;\n    SSL_SESSION_free(sess);\n\n    return self;\n}\n\nstatic int\nossl_SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b)\n{\n    unsigned int a_len;\n    const unsigned char *a_sid = SSL_SESSION_get_id(a, &a_len);\n    unsigned int b_len;\n    const unsigned char *b_sid = SSL_SESSION_get_id(b, &b_len);\n\n    if (SSL_SESSION_get_protocol_version(a) != SSL_SESSION_get_protocol_version(b))\n        return 1;\n    if (a_len != b_len)\n        return 1;\n\n    return CRYPTO_memcmp(a_sid, b_sid, a_len);\n}\n\n/*\n * call-seq:\n *   session1 == session2 -> boolean\n *\n * Returns +true+ if the two Session is the same, +false+ if not.\n */\nstatic VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2)\n{\n    SSL_SESSION *ctx1, *ctx2;\n\n    GetSSLSession(val1, ctx1);\n    GetSSLSession(val2, ctx2);\n\n    switch (ossl_SSL_SESSION_cmp(ctx1, ctx2)) {\n      case 0:         return Qtrue;\n      default:        return Qfalse;\n    }\n}\n\n/*\n * call-seq:\n *    session.time -> Time\n *\n * Returns the time at which the session was established.\n */\nstatic VALUE\nossl_ssl_session_get_time(VALUE self)\n{\n    SSL_SESSION *ctx;\n    long t;\n\n    GetSSLSession(self, ctx);\n    t = SSL_SESSION_get_time(ctx);\n    if (t == 0)\n        return Qnil;\n\n    return rb_funcall(rb_cTime, rb_intern(\"at\"), 1, LONG2NUM(t));\n}\n\n/*\n * call-seq:\n *    session.timeout -> Integer\n *\n * Returns the timeout value set for the session, in seconds from the\n * established time.\n *\n */\nstatic VALUE\nossl_ssl_session_get_timeout(VALUE self)\n{\n    SSL_SESSION *ctx;\n    long t;\n\n    GetSSLSession(self, ctx);\n    t = SSL_SESSION_get_timeout(ctx);\n\n    return LONG2NUM(t);\n}\n\n/*\n * call-seq:\n *    session.time = time\n *    session.time = integer\n *\n * Sets start time of the session. Time resolution is in seconds.\n *\n */\nstatic VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v)\n{\n    SSL_SESSION *ctx;\n    long t;\n\n    GetSSLSession(self, ctx);\n    if (rb_obj_is_instance_of(time_v, rb_cTime)) {\n        time_v = rb_funcall(time_v, rb_intern(\"to_i\"), 0);\n    }\n    t = NUM2LONG(time_v);\n    SSL_SESSION_set_time(ctx, t);\n    return ossl_ssl_session_get_time(self);\n}\n\n/*\n * call-seq:\n *    session.timeout = integer\n *\n * Sets how long until the session expires in seconds.\n */\nstatic VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v)\n{\n    SSL_SESSION *ctx;\n    long t;\n\n    GetSSLSession(self, ctx);\n    t = NUM2LONG(time_v);\n    SSL_SESSION_set_timeout(ctx, t);\n    return ossl_ssl_session_get_timeout(self);\n}\n\n/*\n * call-seq:\n *    session.id -> String\n *\n * Returns the Session ID.\n */\nstatic VALUE ossl_ssl_session_get_id(VALUE self)\n{\n    SSL_SESSION *ctx;\n    const unsigned char *p = NULL;\n    unsigned int i = 0;\n\n    GetSSLSession(self, ctx);\n\n    p = SSL_SESSION_get_id(ctx, &i);\n\n    return rb_str_new((const char *) p, i);\n}\n\n/*\n * call-seq:\n *    session.to_der -> String\n *\n * Returns an ASN1 encoded String that contains the Session object.\n */\nstatic VALUE ossl_ssl_session_to_der(VALUE self)\n{\n    SSL_SESSION *ctx;\n    unsigned char *p;\n    int len;\n    VALUE str;\n\n    GetSSLSession(self, ctx);\n    len = i2d_SSL_SESSION(ctx, NULL);\n    if (len <= 0) {\n        ossl_raise(eSSLSession, \"i2d_SSL_SESSION\");\n    }\n\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    i2d_SSL_SESSION(ctx, &p);\n    ossl_str_adjust(str, p);\n    return str;\n}\n\n/*\n * call-seq:\n *    session.to_pem -> String\n *\n * Returns a PEM encoded String that contains the Session object.\n */\nstatic VALUE ossl_ssl_session_to_pem(VALUE self)\n{\n    SSL_SESSION *ctx;\n    BIO *out;\n\n    GetSSLSession(self, ctx);\n\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eSSLSession, \"BIO_s_mem()\");\n    }\n\n    if (!PEM_write_bio_SSL_SESSION(out, ctx)) {\n        BIO_free(out);\n        ossl_raise(eSSLSession, \"SSL_SESSION_print()\");\n    }\n\n\n    return ossl_membio2str(out);\n}\n\n\n/*\n * call-seq:\n *    session.to_text -> String\n *\n * Shows everything in the Session object. This is for diagnostic purposes.\n */\nstatic VALUE ossl_ssl_session_to_text(VALUE self)\n{\n    SSL_SESSION *ctx;\n    BIO *out;\n\n    GetSSLSession(self, ctx);\n\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eSSLSession, \"BIO_s_mem()\");\n    }\n\n    if (!SSL_SESSION_print(out, ctx)) {\n        BIO_free(out);\n        ossl_raise(eSSLSession, \"SSL_SESSION_print()\");\n    }\n\n    return ossl_membio2str(out);\n}\n\n#endif /* !defined(OPENSSL_NO_SOCK) */\n\nvoid Init_ossl_ssl_session(void)\n{\n#ifndef OPENSSL_NO_SOCK\n    cSSLSession = rb_define_class_under(mSSL, \"Session\", rb_cObject);\n    eSSLSession = rb_define_class_under(cSSLSession, \"SessionError\", eOSSLError);\n\n    rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);\n    rb_define_method(cSSLSession, \"initialize\", ossl_ssl_session_initialize, 1);\n    rb_define_method(cSSLSession, \"initialize_copy\", ossl_ssl_session_initialize_copy, 1);\n\n    rb_define_method(cSSLSession, \"==\", ossl_ssl_session_eq, 1);\n\n    rb_define_method(cSSLSession, \"time\", ossl_ssl_session_get_time, 0);\n    rb_define_method(cSSLSession, \"time=\", ossl_ssl_session_set_time, 1);\n    rb_define_method(cSSLSession, \"timeout\", ossl_ssl_session_get_timeout, 0);\n    rb_define_method(cSSLSession, \"timeout=\", ossl_ssl_session_set_timeout, 1);\n    rb_define_method(cSSLSession, \"id\", ossl_ssl_session_get_id, 0);\n    rb_define_method(cSSLSession, \"to_der\", ossl_ssl_session_to_der, 0);\n    rb_define_method(cSSLSession, \"to_pem\", ossl_ssl_session_to_pem, 0);\n    rb_define_method(cSSLSession, \"to_text\", ossl_ssl_session_to_text, 0);\n#endif /* !defined(OPENSSL_NO_SOCK) */\n}\n"
  },
  {
    "path": "ext/openssl/ossl_ts.c",
    "content": "/*\n *\n * Copyright (C) 2010 Martin Bosslet <Martin.Bosslet@googlemail.com>\n * All rights reserved.\n */\n/*\n * This program is licenced under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#ifndef OPENSSL_NO_TS\n\n#define NewTSRequest(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_ts_req_type, 0)\n#define SetTSRequest(obj, req) do { \\\n    if (!(req)) { \\\n        ossl_raise(rb_eRuntimeError, \"TS_REQ wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (req); \\\n} while (0)\n#define GetTSRequest(obj, req) do { \\\n    TypedData_Get_Struct((obj), TS_REQ, &ossl_ts_req_type, (req)); \\\n    if (!(req)) { \\\n        ossl_raise(rb_eRuntimeError, \"TS_REQ wasn't initialized.\"); \\\n    } \\\n} while (0)\n\n#define NewTSResponse(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_ts_resp_type, 0)\n#define SetTSResponse(obj, resp) do { \\\n    if (!(resp)) { \\\n        ossl_raise(rb_eRuntimeError, \"TS_RESP wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (resp); \\\n} while (0)\n#define GetTSResponse(obj, resp) do { \\\n    TypedData_Get_Struct((obj), TS_RESP, &ossl_ts_resp_type, (resp)); \\\n    if (!(resp)) { \\\n        ossl_raise(rb_eRuntimeError, \"TS_RESP wasn't initialized.\"); \\\n    } \\\n} while (0)\n\n#define NewTSTokenInfo(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_ts_token_info_type, 0)\n#define SetTSTokenInfo(obj, info) do { \\\n    if (!(info)) { \\\n        ossl_raise(rb_eRuntimeError, \"TS_TST_INFO wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (info); \\\n} while (0)\n#define GetTSTokenInfo(obj, info) do { \\\n    TypedData_Get_Struct((obj), TS_TST_INFO, &ossl_ts_token_info_type, (info)); \\\n    if (!(info)) { \\\n        ossl_raise(rb_eRuntimeError, \"TS_TST_INFO wasn't initialized.\"); \\\n    } \\\n} while (0)\n\n#define ossl_tsfac_get_default_policy_id(o)      rb_attr_get((o),rb_intern(\"@default_policy_id\"))\n#define ossl_tsfac_get_serial_number(o)          rb_attr_get((o),rb_intern(\"@serial_number\"))\n#define ossl_tsfac_get_gen_time(o)               rb_attr_get((o),rb_intern(\"@gen_time\"))\n#define ossl_tsfac_get_additional_certs(o)       rb_attr_get((o),rb_intern(\"@additional_certs\"))\n#define ossl_tsfac_get_allowed_digests(o)        rb_attr_get((o),rb_intern(\"@allowed_digests\"))\n\nstatic VALUE mTimestamp;\nstatic VALUE eTimestampError;\nstatic VALUE cTimestampRequest;\nstatic VALUE cTimestampResponse;\nstatic VALUE cTimestampTokenInfo;\nstatic VALUE cTimestampFactory;\nstatic VALUE sBAD_ALG, sBAD_REQUEST, sBAD_DATA_FORMAT, sTIME_NOT_AVAILABLE;\nstatic VALUE sUNACCEPTED_POLICY, sUNACCEPTED_EXTENSION, sADD_INFO_NOT_AVAILABLE;\nstatic VALUE sSYSTEM_FAILURE;\n\nstatic void\nossl_ts_req_free(void *ptr)\n{\n    TS_REQ_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ts_req_type = {\n    \"OpenSSL/Timestamp/Request\",\n    {\n        0, ossl_ts_req_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic void\nossl_ts_resp_free(void *ptr)\n{\n    TS_RESP_free(ptr);\n}\n\nstatic  const rb_data_type_t ossl_ts_resp_type = {\n    \"OpenSSL/Timestamp/Response\",\n    {\n        0, ossl_ts_resp_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic void\nossl_ts_token_info_free(void *ptr)\n{\n    TS_TST_INFO_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_ts_token_info_type = {\n    \"OpenSSL/Timestamp/TokenInfo\",\n    {\n        0, ossl_ts_token_info_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nasn1_to_der(void *template, int (*i2d)(void *template, unsigned char **pp))\n{\n    VALUE str;\n    int len;\n    unsigned char *p;\n\n    if((len = i2d(template, NULL)) <= 0)\n        ossl_raise(eTimestampError, \"Error when encoding to DER\");\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d(template, &p) <= 0)\n        ossl_raise(eTimestampError, \"Error when encoding to DER\");\n    rb_str_set_len(str, p - (unsigned char*)RSTRING_PTR(str));\n\n    return str;\n}\n\nstatic VALUE\nobj_to_asn1obj_i(VALUE obj)\n{\n    return (VALUE)ossl_to_asn1obj(obj);\n}\n\nstatic VALUE\nossl_ts_req_alloc(VALUE klass)\n{\n    TS_REQ *req;\n    VALUE obj;\n\n    obj = NewTSRequest(klass);\n    if (!(req = TS_REQ_new()))\n        ossl_raise(eTimestampError, NULL);\n    SetTSRequest(obj, req);\n\n    /* Defaults */\n    TS_REQ_set_version(req, 1);\n    TS_REQ_set_cert_req(req, 1);\n\n    return obj;\n}\n\n/*\n * When creating a Request with the +File+ or +string+ parameter, the\n * corresponding +File+ or +string+ must be DER-encoded.\n *\n * call-seq:\n *       OpenSSL::Timestamp::Request.new(file)    -> request\n *       OpenSSL::Timestamp::Request.new(string)  -> request\n *       OpenSSL::Timestamp::Request.new          -> empty request\n */\nstatic VALUE\nossl_ts_req_initialize(int argc, VALUE *argv, VALUE self)\n{\n    TS_REQ *ts_req = DATA_PTR(self);\n    BIO *in;\n    VALUE arg;\n\n    if(rb_scan_args(argc, argv, \"01\", &arg) == 0) {\n        return self;\n    }\n\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n    ts_req = d2i_TS_REQ_bio(in, &ts_req);\n    BIO_free(in);\n    if (!ts_req) {\n        DATA_PTR(self) = NULL;\n        ossl_raise(eTimestampError, \"Error when decoding the timestamp request\");\n    }\n    DATA_PTR(self) = ts_req;\n\n    return self;\n}\n\n/*\n * Returns the 'short name' of the object identifier that represents the\n * algorithm that was used to create the message imprint digest.\n *\n *  call-seq:\n *       request.algorithm    -> string\n */\nstatic VALUE\nossl_ts_req_get_algorithm(VALUE self)\n{\n    TS_REQ *req;\n    TS_MSG_IMPRINT *mi;\n    X509_ALGOR *algor;\n    const ASN1_OBJECT *obj;\n\n    GetTSRequest(self, req);\n    mi = TS_REQ_get_msg_imprint(req);\n    algor = TS_MSG_IMPRINT_get_algo(mi);\n    X509_ALGOR_get0(&obj, NULL, NULL, algor);\n    return ossl_asn1obj_to_string(obj);\n}\n\n/*\n * Allows to set the object identifier  or the 'short name' of the\n * algorithm that was used to create the message imprint digest.\n *\n * ===Example:\n *      request.algorithm = \"SHA1\"\n *\n *  call-seq:\n *       request.algorithm = \"string\"    -> string\n */\nstatic VALUE\nossl_ts_req_set_algorithm(VALUE self, VALUE algo)\n{\n    TS_REQ *req;\n    TS_MSG_IMPRINT *mi;\n    ASN1_OBJECT *obj;\n    X509_ALGOR *algor;\n\n    GetTSRequest(self, req);\n    obj = ossl_to_asn1obj(algo);\n    mi = TS_REQ_get_msg_imprint(req);\n    algor = TS_MSG_IMPRINT_get_algo(mi);\n    if (!X509_ALGOR_set0(algor, obj, V_ASN1_NULL, NULL)) {\n        ASN1_OBJECT_free(obj);\n        ossl_raise(eTimestampError, \"X509_ALGOR_set0\");\n    }\n\n    return algo;\n}\n\n/*\n * Returns the message imprint (digest) of the data to be timestamped.\n *\n * call-seq:\n *       request.message_imprint    -> string or nil\n */\nstatic VALUE\nossl_ts_req_get_msg_imprint(VALUE self)\n{\n    TS_REQ *req;\n    TS_MSG_IMPRINT *mi;\n    ASN1_OCTET_STRING *hashed_msg;\n    VALUE ret;\n\n    GetTSRequest(self, req);\n    mi = TS_REQ_get_msg_imprint(req);\n    hashed_msg = TS_MSG_IMPRINT_get_msg(mi);\n\n    ret = asn1str_to_str(hashed_msg);\n\n    return ret;\n}\n\n/*\n * Set the message imprint digest.\n *\n *  call-seq:\n *       request.message_imprint = \"string\"    -> string\n */\nstatic VALUE\nossl_ts_req_set_msg_imprint(VALUE self, VALUE hash)\n{\n    TS_REQ *req;\n    TS_MSG_IMPRINT *mi;\n    StringValue(hash);\n\n    GetTSRequest(self, req);\n    mi = TS_REQ_get_msg_imprint(req);\n    if (!TS_MSG_IMPRINT_set_msg(mi, (unsigned char *)RSTRING_PTR(hash), RSTRING_LENINT(hash)))\n        ossl_raise(eTimestampError, \"TS_MSG_IMPRINT_set_msg\");\n\n    return hash;\n}\n\n/*\n * Returns the version of this request. +1+ is the default value.\n *\n * call-seq:\n *       request.version -> Integer\n */\nstatic VALUE\nossl_ts_req_get_version(VALUE self)\n{\n    TS_REQ *req;\n\n    GetTSRequest(self, req);\n    return LONG2NUM(TS_REQ_get_version(req));\n}\n\n/*\n * Sets the version number for this Request. This should be +1+ for compliant\n * servers.\n *\n * call-seq:\n *       request.version = number    -> Integer\n */\nstatic VALUE\nossl_ts_req_set_version(VALUE self, VALUE version)\n{\n    TS_REQ *req;\n    long ver;\n\n    if ((ver = NUM2LONG(version)) < 0)\n        ossl_raise(eTimestampError, \"version must be >= 0!\");\n    GetTSRequest(self, req);\n    if (!TS_REQ_set_version(req, ver))\n        ossl_raise(eTimestampError, \"TS_REQ_set_version\");\n\n    return version;\n}\n\n/*\n * Returns the 'short name' of the object identifier that represents the\n * timestamp policy under which the server shall create the timestamp.\n *\n * call-seq:\n *       request.policy_id    -> string or nil\n */\nstatic VALUE\nossl_ts_req_get_policy_id(VALUE self)\n{\n    TS_REQ *req;\n\n    GetTSRequest(self, req);\n    if (!TS_REQ_get_policy_id(req))\n        return Qnil;\n    return ossl_asn1obj_to_string(TS_REQ_get_policy_id(req));\n}\n\n/*\n * Allows to set the object identifier that represents the\n * timestamp policy under which the server shall create the timestamp. This\n * may be left +nil+, implying that the timestamp server will issue the\n * timestamp using some default policy.\n *\n * ===Example:\n *      request.policy_id = \"1.2.3.4.5\"\n *\n * call-seq:\n *       request.policy_id = \"string\"   -> string\n */\nstatic VALUE\nossl_ts_req_set_policy_id(VALUE self, VALUE oid)\n{\n    TS_REQ *req;\n    ASN1_OBJECT *obj;\n    int ok;\n\n    GetTSRequest(self, req);\n    obj = ossl_to_asn1obj(oid);\n    ok = TS_REQ_set_policy_id(req, obj);\n    ASN1_OBJECT_free(obj);\n    if (!ok)\n        ossl_raise(eTimestampError, \"TS_REQ_set_policy_id\");\n\n    return oid;\n}\n\n/*\n * Returns the nonce (number used once) that the server shall include in its\n * response.\n *\n * call-seq:\n *       request.nonce    -> BN or nil\n */\nstatic VALUE\nossl_ts_req_get_nonce(VALUE self)\n{\n    TS_REQ *req;\n    const ASN1_INTEGER * nonce;\n\n    GetTSRequest(self, req);\n    if (!(nonce = TS_REQ_get_nonce(req)))\n        return Qnil;\n    return asn1integer_to_num(nonce);\n}\n\n/*\n * Sets the nonce (number used once) that the server shall include in its\n * response. If the nonce is set, the server must return the same nonce value in\n * a valid Response.\n *\n * call-seq:\n *       request.nonce = number    -> BN\n */\nstatic VALUE\nossl_ts_req_set_nonce(VALUE self, VALUE num)\n{\n    TS_REQ *req;\n    ASN1_INTEGER *nonce;\n    int ok;\n\n    GetTSRequest(self, req);\n    nonce = num_to_asn1integer(num, NULL);\n    ok = TS_REQ_set_nonce(req, nonce);\n    ASN1_INTEGER_free(nonce);\n    if (!ok)\n        ossl_raise(eTimestampError, NULL);\n    return num;\n}\n\n/*\n * Indicates whether the response shall contain the timestamp authority's\n * certificate or not.\n *\n * call-seq:\n *       request.cert_requested?  -> true or false\n */\nstatic VALUE\nossl_ts_req_get_cert_requested(VALUE self)\n{\n    TS_REQ *req;\n\n    GetTSRequest(self, req);\n    return TS_REQ_get_cert_req(req) ? Qtrue: Qfalse;\n}\n\n/*\n * Specify whether the response shall contain the timestamp authority's\n * certificate or not. The default value is +true+.\n *\n * call-seq:\n *       request.cert_requested = boolean -> true or false\n */\nstatic VALUE\nossl_ts_req_set_cert_requested(VALUE self, VALUE requested)\n{\n    TS_REQ *req;\n\n    GetTSRequest(self, req);\n    TS_REQ_set_cert_req(req, RTEST(requested));\n\n    return requested;\n}\n\n/*\n * DER-encodes this Request.\n *\n * call-seq:\n *       request.to_der    -> DER-encoded string\n */\nstatic VALUE\nossl_ts_req_to_der(VALUE self)\n{\n    TS_REQ *req;\n    TS_MSG_IMPRINT *mi;\n    X509_ALGOR *algo;\n    const ASN1_OBJECT *obj;\n    ASN1_OCTET_STRING *hashed_msg;\n\n    GetTSRequest(self, req);\n    mi = TS_REQ_get_msg_imprint(req);\n\n    algo = TS_MSG_IMPRINT_get_algo(mi);\n    X509_ALGOR_get0(&obj, NULL, NULL, algo);\n    if (OBJ_obj2nid(obj) == NID_undef)\n        ossl_raise(eTimestampError, \"Message imprint missing algorithm\");\n\n    hashed_msg = TS_MSG_IMPRINT_get_msg(mi);\n    if (!ASN1_STRING_length(hashed_msg))\n        ossl_raise(eTimestampError, \"Message imprint missing hashed message\");\n\n    return asn1_to_der((void *)req, (int (*)(void *, unsigned char **))i2d_TS_REQ);\n}\n\nstatic VALUE\nossl_ts_req_to_text(VALUE self)\n{\n    TS_REQ *req;\n    BIO *out;\n\n    GetTSRequest(self, req);\n\n    out = BIO_new(BIO_s_mem());\n    if (!out) ossl_raise(eTimestampError, NULL);\n\n    if (!TS_REQ_print_bio(out, req)) {\n        BIO_free(out);\n        ossl_raise(eTimestampError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\nstatic VALUE\nossl_ts_resp_alloc(VALUE klass)\n{\n    TS_RESP *resp;\n    VALUE obj;\n\n    obj = NewTSResponse(klass);\n    if (!(resp = TS_RESP_new()))\n        ossl_raise(eTimestampError, NULL);\n    SetTSResponse(obj, resp);\n\n    return obj;\n}\n\n/*\n * Creates a Response from a +File+ or +string+ parameter, the\n * corresponding +File+ or +string+ must be DER-encoded. Please note\n * that Response is an immutable read-only class. If you'd like to create\n * timestamps please refer to Factory instead.\n *\n * call-seq:\n *       OpenSSL::Timestamp::Response.new(file)    -> response\n *       OpenSSL::Timestamp::Response.new(string)  -> response\n */\nstatic VALUE\nossl_ts_resp_initialize(VALUE self, VALUE der)\n{\n    TS_RESP *ts_resp = DATA_PTR(self);\n    BIO *in;\n\n    der = ossl_to_der_if_possible(der);\n    in  = ossl_obj2bio(&der);\n    ts_resp = d2i_TS_RESP_bio(in, &ts_resp);\n    BIO_free(in);\n    if (!ts_resp) {\n        DATA_PTR(self) = NULL;\n        ossl_raise(eTimestampError, \"Error when decoding the timestamp response\");\n    }\n    DATA_PTR(self) = ts_resp;\n\n    return self;\n}\n\n/*\n * Returns one of GRANTED, GRANTED_WITH_MODS, REJECTION, WAITING,\n * REVOCATION_WARNING or REVOCATION_NOTIFICATION. A timestamp token has\n * been created only in case +status+ is equal to GRANTED or GRANTED_WITH_MODS.\n *\n * call-seq:\n *       response.status -> BN (never nil)\n */\nstatic VALUE\nossl_ts_resp_get_status(VALUE self)\n{\n    TS_RESP *resp;\n    TS_STATUS_INFO *si;\n    const ASN1_INTEGER *st;\n\n    GetTSResponse(self, resp);\n    si = TS_RESP_get_status_info(resp);\n    st = TS_STATUS_INFO_get0_status(si);\n\n    return asn1integer_to_num(st);\n}\n\n/*\n * In cases no timestamp token has been created, this field contains further\n * info about the reason why response creation failed. The method returns either\n * nil (the request was successful and a timestamp token was created) or one of\n * the following:\n * * :BAD_ALG - Indicates that the timestamp server rejects the message\n *   imprint algorithm used in the Request\n * * :BAD_REQUEST - Indicates that the timestamp server was not able to process\n *   the Request properly\n * * :BAD_DATA_FORMAT - Indicates that the timestamp server was not able to\n *   parse certain data in the Request\n * * :TIME_NOT_AVAILABLE - Indicates that the server could not access its time\n *   source\n * * :UNACCEPTED_POLICY - Indicates that the requested policy identifier is not\n *   recognized or supported by the timestamp server\n * * :UNACCEPTED_EXTENSIION - Indicates that an extension in the Request is\n *   not supported by the timestamp server\n * * :ADD_INFO_NOT_AVAILABLE -Indicates that additional information requested\n *   is either not understood or currently not available\n * * :SYSTEM_FAILURE - Timestamp creation failed due to an internal error that\n *   occurred on the timestamp server\n *\n * call-seq:\n *       response.failure_info -> nil or symbol\n */\nstatic VALUE\nossl_ts_resp_get_failure_info(VALUE self)\n{\n    TS_RESP *resp;\n    TS_STATUS_INFO *si;\n    const ASN1_BIT_STRING *fi;\n\n    GetTSResponse(self, resp);\n    si = TS_RESP_get_status_info(resp);\n    fi = TS_STATUS_INFO_get0_failure_info(si);\n    if (!fi)\n        return Qnil;\n    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_ALG))\n        return sBAD_ALG;\n    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_REQUEST))\n        return sBAD_REQUEST;\n    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_BAD_DATA_FORMAT))\n        return sBAD_DATA_FORMAT;\n    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_TIME_NOT_AVAILABLE))\n        return sTIME_NOT_AVAILABLE;\n    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_UNACCEPTED_POLICY))\n        return sUNACCEPTED_POLICY;\n    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_UNACCEPTED_EXTENSION))\n        return sUNACCEPTED_EXTENSION;\n    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_ADD_INFO_NOT_AVAILABLE))\n        return sADD_INFO_NOT_AVAILABLE;\n    if (ASN1_BIT_STRING_get_bit(fi, TS_INFO_SYSTEM_FAILURE))\n        return sSYSTEM_FAILURE;\n\n    ossl_raise(eTimestampError, \"Unrecognized failure info.\");\n}\n\n/*\n * In cases of failure this field may contain an array of strings further\n * describing the origin of the failure.\n *\n * call-seq:\n *       response.status_text -> Array of strings or nil\n */\nstatic VALUE\nossl_ts_resp_get_status_text(VALUE self)\n{\n    TS_RESP *resp;\n    TS_STATUS_INFO *si;\n    const STACK_OF(ASN1_UTF8STRING) *text;\n    ASN1_UTF8STRING *current;\n    int i;\n    VALUE ret = rb_ary_new();\n\n    GetTSResponse(self, resp);\n    si = TS_RESP_get_status_info(resp);\n    if ((text = TS_STATUS_INFO_get0_text(si))) {\n        for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) {\n            current = sk_ASN1_UTF8STRING_value(text, i);\n            rb_ary_push(ret, asn1str_to_str(current));\n        }\n    }\n\n    return ret;\n}\n\n/*\n * If a timestamp token is present, this returns it in the form of a\n * OpenSSL::PKCS7.\n *\n * call-seq:\n *       response.token -> nil or OpenSSL::PKCS7\n */\nstatic VALUE\nossl_ts_resp_get_token(VALUE self)\n{\n    TS_RESP *resp;\n    PKCS7 *p7;\n\n    GetTSResponse(self, resp);\n    if (!(p7 = TS_RESP_get_token(resp)))\n        return Qnil;\n    return ossl_pkcs7_new(p7);\n}\n\n/*\n * Get the response's token info if present.\n *\n * call-seq:\n *       response.token_info -> nil or OpenSSL::Timestamp::TokenInfo\n */\nstatic VALUE\nossl_ts_resp_get_token_info(VALUE self)\n{\n    TS_RESP *resp;\n    TS_TST_INFO *info, *copy;\n    VALUE obj;\n\n    GetTSResponse(self, resp);\n    if (!(info = TS_RESP_get_tst_info(resp)))\n        return Qnil;\n\n    obj = NewTSTokenInfo(cTimestampTokenInfo);\n\n    if (!(copy = TS_TST_INFO_dup(info)))\n        ossl_raise(eTimestampError, NULL);\n\n    SetTSTokenInfo(obj, copy);\n\n    return obj;\n}\n\n/*\n * If the Request specified to request the TSA certificate\n * (Request#cert_requested = true), then this field contains the\n * certificate of the timestamp authority.\n *\n * call-seq:\n *       response.tsa_certificate -> OpenSSL::X509::Certificate or nil\n */\nstatic VALUE\nossl_ts_resp_get_tsa_certificate(VALUE self)\n{\n    TS_RESP *resp;\n    PKCS7 *p7;\n    PKCS7_SIGNER_INFO *ts_info;\n    const X509 *cert;\n\n    GetTSResponse(self, resp);\n    if (!(p7 = TS_RESP_get_token(resp)))\n        return Qnil;\n    ts_info = sk_PKCS7_SIGNER_INFO_value(p7->d.sign->signer_info, 0);\n    cert = PKCS7_cert_from_signer_info(p7, ts_info);\n    if (!cert)\n        return Qnil;\n    return ossl_x509_new(cert);\n}\n\n/*\n * Returns the Response in DER-encoded form.\n *\n * call-seq:\n *       response.to_der -> string\n */\nstatic VALUE\nossl_ts_resp_to_der(VALUE self)\n{\n    TS_RESP *resp;\n\n    GetTSResponse(self, resp);\n    return asn1_to_der((void *)resp, (int (*)(void *, unsigned char **))i2d_TS_RESP);\n}\n\nstatic VALUE\nossl_ts_resp_to_text(VALUE self)\n{\n    TS_RESP *resp;\n    BIO *out;\n\n    GetTSResponse(self, resp);\n\n    out = BIO_new(BIO_s_mem());\n    if (!out) ossl_raise(eTimestampError, NULL);\n\n    if (!TS_RESP_print_bio(out, resp)) {\n        BIO_free(out);\n        ossl_raise(eTimestampError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\n/*\n * Verifies a timestamp token by checking the signature, validating the\n * certificate chain implied by tsa_certificate and by checking conformance to\n * a given Request. Mandatory parameters are the Request associated to this\n * Response, and an OpenSSL::X509::Store of trusted roots.\n *\n * Intermediate certificates can optionally be supplied for creating the\n * certificate chain. These intermediate certificates must all be\n * instances of OpenSSL::X509::Certificate.\n *\n * If validation fails, several kinds of exceptions can be raised:\n * * TypeError if types don't fit\n * * TimestampError if something is wrong with the timestamp token itself, if\n *   it is not conformant to the Request, or if validation of the timestamp\n *   certificate chain fails.\n *\n * call-seq:\n *       response.verify(Request, root_store) -> Response\n *       response.verify(Request, root_store, [intermediate_cert]) -> Response\n */\nstatic VALUE\nossl_ts_resp_verify(int argc, VALUE *argv, VALUE self)\n{\n    VALUE ts_req, store, intermediates;\n    TS_RESP *resp;\n    TS_REQ *req;\n    X509_STORE *x509st;\n    TS_VERIFY_CTX *ctx;\n    STACK_OF(X509) *x509inter = NULL;\n    PKCS7* p7;\n    X509 *cert;\n    int status, i, ok;\n\n    rb_scan_args(argc, argv, \"21\", &ts_req, &store, &intermediates);\n\n    GetTSResponse(self, resp);\n    GetTSRequest(ts_req, req);\n    x509st = GetX509StorePtr(store);\n\n    if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(req, NULL))) {\n        ossl_raise(eTimestampError, \"Error when creating the verification context.\");\n    }\n\n    if (!NIL_P(intermediates)) {\n        x509inter = ossl_protect_x509_ary2sk(intermediates, &status);\n        if (status) {\n            TS_VERIFY_CTX_free(ctx);\n            rb_jump_tag(status);\n        }\n    } else if (!(x509inter = sk_X509_new_null())) {\n        TS_VERIFY_CTX_free(ctx);\n        ossl_raise(eTimestampError, \"sk_X509_new_null\");\n    }\n\n    if (!(p7 = TS_RESP_get_token(resp))) {\n        TS_VERIFY_CTX_free(ctx);\n        sk_X509_pop_free(x509inter, X509_free);\n        ossl_raise(eTimestampError, \"TS_RESP_get_token\");\n    }\n    for (i=0; i < sk_X509_num(p7->d.sign->cert); i++) {\n        cert = sk_X509_value(p7->d.sign->cert, i);\n        if (!sk_X509_push(x509inter, cert)) {\n            sk_X509_pop_free(x509inter, X509_free);\n            TS_VERIFY_CTX_free(ctx);\n            ossl_raise(eTimestampError, \"sk_X509_push\");\n        }\n        X509_up_ref(cert);\n    }\n\n    if (!X509_STORE_up_ref(x509st)) {\n        sk_X509_pop_free(x509inter, X509_free);\n        TS_VERIFY_CTX_free(ctx);\n        ossl_raise(eTimestampError, \"X509_STORE_up_ref\");\n    }\n\n#ifdef HAVE_TS_VERIFY_CTX_SET0_CERTS\n    TS_VERIFY_CTX_set0_certs(ctx, x509inter);\n    TS_VERIFY_CTX_set0_store(ctx, x509st);\n#else\n# if OSSL_OPENSSL_PREREQ(3, 0, 0) || OSSL_IS_LIBRESSL\n    TS_VERIFY_CTX_set_certs(ctx, x509inter);\n# else\n    TS_VERIFY_CTS_set_certs(ctx, x509inter);\n# endif\n    TS_VERIFY_CTX_set_store(ctx, x509st);\n#endif\n    TS_VERIFY_CTX_add_flags(ctx, TS_VFY_SIGNATURE);\n\n    ok = TS_RESP_verify_response(ctx, resp);\n    TS_VERIFY_CTX_free(ctx);\n\n    if (!ok)\n        ossl_raise(eTimestampError, \"TS_RESP_verify_response\");\n\n    return self;\n}\n\nstatic VALUE\nossl_ts_token_info_alloc(VALUE klass)\n{\n    TS_TST_INFO *info;\n    VALUE obj;\n\n    obj = NewTSTokenInfo(klass);\n    if (!(info = TS_TST_INFO_new()))\n        ossl_raise(eTimestampError, NULL);\n    SetTSTokenInfo(obj, info);\n\n    return obj;\n}\n\n/*\n * Creates a TokenInfo from a +File+ or +string+ parameter, the\n * corresponding +File+ or +string+ must be DER-encoded. Please note\n * that TokenInfo is an immutable read-only class. If you'd like to create\n * timestamps please refer to Factory instead.\n *\n * call-seq:\n *       OpenSSL::Timestamp::TokenInfo.new(file)    -> token-info\n *       OpenSSL::Timestamp::TokenInfo.new(string)  -> token-info\n */\nstatic VALUE\nossl_ts_token_info_initialize(VALUE self, VALUE der)\n{\n    TS_TST_INFO *info = DATA_PTR(self);\n    BIO *in;\n\n    der = ossl_to_der_if_possible(der);\n    in  = ossl_obj2bio(&der);\n    info = d2i_TS_TST_INFO_bio(in, &info);\n    BIO_free(in);\n    if (!info) {\n        DATA_PTR(self) = NULL;\n        ossl_raise(eTimestampError, \"Error when decoding the timestamp token info\");\n    }\n    DATA_PTR(self) = info;\n\n    return self;\n}\n\n/*\n * Returns the version number of the token info. With compliant servers,\n * this value should be +1+ if present. If status is GRANTED or\n * GRANTED_WITH_MODS.\n *\n * call-seq:\n *       token_info.version -> Integer or nil\n */\nstatic VALUE\nossl_ts_token_info_get_version(VALUE self)\n{\n    TS_TST_INFO *info;\n\n    GetTSTokenInfo(self, info);\n    return LONG2NUM(TS_TST_INFO_get_version(info));\n}\n\n/*\n * Returns the timestamp policy object identifier of the policy this timestamp\n * was created under. If status is GRANTED or GRANTED_WITH_MODS, this is never\n * +nil+.\n *\n * ===Example:\n *      id = token_info.policy_id\n *      puts id                 -> \"1.2.3.4.5\"\n *\n * call-seq:\n *       token_info.policy_id -> string or nil\n */\nstatic VALUE\nossl_ts_token_info_get_policy_id(VALUE self)\n{\n    TS_TST_INFO *info;\n\n    GetTSTokenInfo(self, info);\n    return ossl_asn1obj_to_string(TS_TST_INFO_get_policy_id(info));\n}\n\n/*\n * Returns the 'short name' of the object identifier representing the algorithm\n * that was used to derive the message imprint digest. For valid timestamps,\n * this is the same value that was already given in the Request. If status is\n * GRANTED or GRANTED_WITH_MODS, this is never +nil+.\n *\n * ===Example:\n *      algo = token_info.algorithm\n *      puts algo                -> \"SHA1\"\n *\n * call-seq:\n *       token_info.algorithm -> string or nil\n */\nstatic VALUE\nossl_ts_token_info_get_algorithm(VALUE self)\n{\n    TS_TST_INFO *info;\n    TS_MSG_IMPRINT *mi;\n    X509_ALGOR *algo;\n    const ASN1_OBJECT *obj;\n\n    GetTSTokenInfo(self, info);\n    mi = TS_TST_INFO_get_msg_imprint(info);\n    algo = TS_MSG_IMPRINT_get_algo(mi);\n    X509_ALGOR_get0(&obj, NULL, NULL, algo);\n    return ossl_asn1obj_to_string(obj);\n}\n\n/*\n * Returns the message imprint digest. For valid timestamps,\n * this is the same value that was already given in the Request.\n * If status is GRANTED or GRANTED_WITH_MODS, this is never +nil+.\n *\n * ===Example:\n *      mi = token_info.msg_imprint\n *      puts mi                -> \"DEADBEEF\"\n *\n * call-seq:\n *       token_info.msg_imprint -> string.\n */\nstatic VALUE\nossl_ts_token_info_get_msg_imprint(VALUE self)\n{\n    TS_TST_INFO *info;\n    TS_MSG_IMPRINT *mi;\n    ASN1_OCTET_STRING *hashed_msg;\n    VALUE ret;\n\n    GetTSTokenInfo(self, info);\n    mi = TS_TST_INFO_get_msg_imprint(info);\n    hashed_msg = TS_MSG_IMPRINT_get_msg(mi);\n    ret = asn1str_to_str(hashed_msg);\n\n    return ret;\n}\n\n/*\n * Returns serial number of the timestamp token. This value shall never be the\n * same for two timestamp tokens issued by a dedicated timestamp authority.\n * If status is GRANTED or GRANTED_WITH_MODS, this is never +nil+.\n *\n * call-seq:\n *       token_info.serial_number -> BN or nil\n */\nstatic VALUE\nossl_ts_token_info_get_serial_number(VALUE self)\n{\n    TS_TST_INFO *info;\n\n    GetTSTokenInfo(self, info);\n    return asn1integer_to_num(TS_TST_INFO_get_serial(info));\n}\n\n/*\n * Returns time when this timestamp token was created. If status is GRANTED or\n * GRANTED_WITH_MODS, this is never +nil+.\n *\n * call-seq:\n *       token_info.gen_time -> Time\n */\nstatic VALUE\nossl_ts_token_info_get_gen_time(VALUE self)\n{\n    TS_TST_INFO *info;\n\n    GetTSTokenInfo(self, info);\n    return asn1time_to_time(TS_TST_INFO_get_time(info));\n}\n\n/*\n * If the ordering field is missing, or if the ordering field is present\n * and set to false, then the genTime field only indicates the time at\n * which the time-stamp token has been created by the TSA.  In such a\n * case, the ordering of time-stamp tokens issued by the same TSA or\n * different TSAs is only possible when the difference between the\n * genTime of the first time-stamp token and the genTime of the second\n * time-stamp token is greater than the sum of the accuracies of the\n * genTime for each time-stamp token.\n *\n * If the ordering field is present and set to true, every time-stamp\n * token from the same TSA can always be ordered based on the genTime\n * field, regardless of the genTime accuracy.\n *\n * call-seq:\n *       token_info.ordering -> true, falses or nil\n */\nstatic VALUE\nossl_ts_token_info_get_ordering(VALUE self)\n{\n    TS_TST_INFO *info;\n\n    GetTSTokenInfo(self, info);\n    return TS_TST_INFO_get_ordering(info) ? Qtrue : Qfalse;\n}\n\n/*\n * If the timestamp token is valid then this field contains the same nonce that\n * was passed to the timestamp server in the initial Request.\n *\n * call-seq:\n *       token_info.nonce -> BN or nil\n */\nstatic VALUE\nossl_ts_token_info_get_nonce(VALUE self)\n{\n    TS_TST_INFO *info;\n    const ASN1_INTEGER *nonce;\n\n    GetTSTokenInfo(self, info);\n    if (!(nonce = TS_TST_INFO_get_nonce(info)))\n        return Qnil;\n\n    return asn1integer_to_num(nonce);\n}\n\n/*\n * Returns the TokenInfo in DER-encoded form.\n *\n * call-seq:\n *       token_info.to_der -> string\n */\nstatic VALUE\nossl_ts_token_info_to_der(VALUE self)\n{\n    TS_TST_INFO *info;\n\n    GetTSTokenInfo(self, info);\n    return asn1_to_der((void *)info, (int (*)(void *, unsigned char **))i2d_TS_TST_INFO);\n}\n\nstatic VALUE\nossl_ts_token_info_to_text(VALUE self)\n{\n    TS_TST_INFO *info;\n    BIO *out;\n\n    GetTSTokenInfo(self, info);\n\n    out = BIO_new(BIO_s_mem());\n    if (!out) ossl_raise(eTimestampError, NULL);\n\n    if (!TS_TST_INFO_print_bio(out, info)) {\n        BIO_free(out);\n        ossl_raise(eTimestampError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\nstatic ASN1_INTEGER *\nossl_tsfac_serial_cb(struct TS_resp_ctx *ctx, void *data)\n{\n    ASN1_INTEGER **snptr = (ASN1_INTEGER **)data;\n    ASN1_INTEGER *sn = *snptr;\n    *snptr = NULL;\n    return sn;\n}\n\nstatic int\n#if !defined(LIBRESSL_VERSION_NUMBER)\nossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, long *sec, long *usec)\n#else\nossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, time_t *sec, long *usec)\n#endif\n{\n    *sec = *((long *)data);\n    *usec = 0;\n    return 1;\n}\n\nstatic VALUE\nossl_evp_md_fetch_i(VALUE args_)\n{\n    VALUE *args = (VALUE *)args_, md_holder;\n    const EVP_MD *md;\n\n    md = ossl_evp_md_fetch(args[1], &md_holder);\n    rb_ary_push(args[0], md_holder);\n    return (VALUE)md;\n}\n\nstatic VALUE\nossl_obj2bio_i(VALUE arg)\n{\n    return (VALUE)ossl_obj2bio((VALUE *)arg);\n}\n\n/*\n * Creates a Response with the help of an OpenSSL::PKey, an\n * OpenSSL::X509::Certificate and a Request.\n *\n * Mandatory parameters for timestamp creation that need to be set in the\n * Request:\n *\n * * Request#algorithm\n * * Request#message_imprint\n *\n * Mandatory parameters that need to be set in the Factory:\n * * Factory#serial_number\n * * Factory#gen_time\n * * Factory#allowed_digests\n *\n * In addition one of either Request#policy_id or Factory#default_policy_id\n * must be set.\n *\n * Raises a TimestampError if creation fails, though successfully created error\n * responses may be returned.\n *\n * call-seq:\n *       factory.create_timestamp(key, certificate, request) -> Response\n */\nstatic VALUE\nossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)\n{\n    VALUE serial_number, def_policy_id, gen_time, additional_certs,\n          allowed_digests, allowed_digests_tmp = Qnil;\n    VALUE str;\n    STACK_OF(X509) *inter_certs;\n    VALUE tsresp, ret = Qnil;\n    EVP_PKEY *sign_key;\n    X509 *tsa_cert;\n    TS_REQ *req;\n    TS_RESP *response = NULL;\n    TS_RESP_CTX *ctx = NULL;\n    BIO *req_bio;\n    ASN1_INTEGER *asn1_serial = NULL;\n    ASN1_OBJECT *def_policy_id_obj = NULL;\n    long lgen_time;\n    const char * err_msg = NULL;\n    int status = 0;\n\n    tsresp = NewTSResponse(cTimestampResponse);\n    tsa_cert = GetX509CertPtr(certificate);\n    sign_key = GetPrivPKeyPtr(key);\n    GetTSRequest(request, req);\n\n    gen_time = ossl_tsfac_get_gen_time(self);\n    if (!rb_obj_is_instance_of(gen_time, rb_cTime)) {\n        err_msg = \"@gen_time must be a Time.\";\n        goto end;\n    }\n    lgen_time = NUM2LONG(rb_funcall(gen_time, rb_intern(\"to_i\"), 0));\n\n    serial_number = ossl_tsfac_get_serial_number(self);\n    if (NIL_P(serial_number)) {\n        err_msg = \"@serial_number must be set.\";\n        goto end;\n    }\n    asn1_serial = num_to_asn1integer(serial_number, NULL);\n\n    def_policy_id = ossl_tsfac_get_default_policy_id(self);\n    if (NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) {\n        err_msg = \"No policy id in the request and no default policy set\";\n        goto end;\n    }\n    if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) {\n        def_policy_id_obj = (ASN1_OBJECT*)rb_protect(obj_to_asn1obj_i, (VALUE)def_policy_id, &status);\n        if (status)\n            goto end;\n    }\n\n    if (!(ctx = TS_RESP_CTX_new())) {\n        err_msg = \"Memory allocation failed.\";\n        goto end;\n    }\n\n    TS_RESP_CTX_set_serial_cb(ctx, ossl_tsfac_serial_cb, &asn1_serial);\n    if (!TS_RESP_CTX_set_signer_cert(ctx, tsa_cert)) {\n        err_msg = \"Certificate does not contain the timestamping extension\";\n        goto end;\n    }\n\n    additional_certs = ossl_tsfac_get_additional_certs(self);\n    if (rb_obj_is_kind_of(additional_certs, rb_cArray)) {\n        inter_certs = ossl_protect_x509_ary2sk(additional_certs, &status);\n        if (status)\n            goto end;\n\n        /* this dups the sk_X509 and ups each cert's ref count */\n        TS_RESP_CTX_set_certs(ctx, inter_certs);\n        sk_X509_pop_free(inter_certs, X509_free);\n    }\n\n    TS_RESP_CTX_set_signer_key(ctx, sign_key);\n    if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req))\n        TS_RESP_CTX_set_def_policy(ctx, def_policy_id_obj);\n    if (TS_REQ_get_policy_id(req))\n        TS_RESP_CTX_set_def_policy(ctx, TS_REQ_get_policy_id(req));\n    TS_RESP_CTX_set_time_cb(ctx, ossl_tsfac_time_cb, &lgen_time);\n\n    allowed_digests = ossl_tsfac_get_allowed_digests(self);\n    if (rb_obj_is_kind_of(allowed_digests, rb_cArray)) {\n        allowed_digests_tmp = rb_ary_new_capa(RARRAY_LEN(allowed_digests));\n        for (long i = 0; i < RARRAY_LEN(allowed_digests); i++) {\n            VALUE args[] = {\n                allowed_digests_tmp,\n                rb_ary_entry(allowed_digests, i),\n            };\n            const EVP_MD *md = (const EVP_MD *)rb_protect(ossl_evp_md_fetch_i,\n                                                          (VALUE)args, &status);\n            if (status)\n                goto end;\n            if (!TS_RESP_CTX_add_md(ctx, md))\n                goto end;\n        }\n    }\n\n    str = rb_protect(ossl_to_der, request, &status);\n    if (status)\n        goto end;\n\n    req_bio = (BIO*)rb_protect(ossl_obj2bio_i, (VALUE)&str, &status);\n    if (status)\n        goto end;\n\n    response = TS_RESP_create_response(ctx, req_bio);\n    BIO_free(req_bio);\n    RB_GC_GUARD(allowed_digests_tmp);\n\n    if (!response) {\n        err_msg = \"Error during response generation\";\n        goto end;\n    }\n\n    /* bad responses aren't exceptional, but openssl still sets error\n     * information. */\n    ossl_clear_error();\n\n    SetTSResponse(tsresp, response);\n    ret = tsresp;\n\n  end:\n    ASN1_INTEGER_free(asn1_serial);\n    ASN1_OBJECT_free(def_policy_id_obj);\n    TS_RESP_CTX_free(ctx);\n    if (err_msg)\n        rb_exc_raise(ossl_make_error(eTimestampError, rb_str_new_cstr(err_msg)));\n    if (status)\n        rb_jump_tag(status);\n    return ret;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_ts(void)\n{\n    /*\n     * Possible return value for +Response#failure_info+. Indicates that the\n     * timestamp server rejects the message imprint algorithm used in the\n     * +Request+\n     */\n    sBAD_ALG = ID2SYM(rb_intern_const(\"BAD_ALG\"));\n\n    /*\n     * Possible return value for +Response#failure_info+. Indicates that the\n     * timestamp server was not able to process the +Request+ properly.\n     */\n    sBAD_REQUEST = ID2SYM(rb_intern_const(\"BAD_REQUEST\"));\n    /*\n     * Possible return value for +Response#failure_info+. Indicates that the\n     * timestamp server was not able to parse certain data in the +Request+.\n     */\n    sBAD_DATA_FORMAT = ID2SYM(rb_intern_const(\"BAD_DATA_FORMAT\"));\n\n    sTIME_NOT_AVAILABLE = ID2SYM(rb_intern_const(\"TIME_NOT_AVAILABLE\"));\n    sUNACCEPTED_POLICY = ID2SYM(rb_intern_const(\"UNACCEPTED_POLICY\"));\n    sUNACCEPTED_EXTENSION = ID2SYM(rb_intern_const(\"UNACCEPTED_EXTENSION\"));\n    sADD_INFO_NOT_AVAILABLE = ID2SYM(rb_intern_const(\"ADD_INFO_NOT_AVAILABLE\"));\n    sSYSTEM_FAILURE = ID2SYM(rb_intern_const(\"SYSTEM_FAILURE\"));\n\n    /* Document-class: OpenSSL::Timestamp\n     * Provides classes and methods to request, create and validate\n     * {RFC3161-compliant}[http://www.ietf.org/rfc/rfc3161.txt] timestamps.\n     * Request may be used to either create requests from scratch or to parse\n     * existing requests that again can be used to request timestamps from a\n     * timestamp server, e.g. via the net/http. The resulting timestamp\n     * response may be parsed using Response.\n     *\n     * Please note that Response is read-only and immutable. To create a\n     * Response, an instance of Factory as well as a valid Request are needed.\n     *\n     * ===Create a Response:\n     *      #Assumes ts.p12 is a PKCS#12-compatible file with a private key\n     *      #and a certificate that has an extended key usage of 'timeStamping'\n     *      p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd')\n     *      md = OpenSSL::Digest.new('SHA1')\n     *      hash = md.digest(data) #some binary data to be timestamped\n     *      req = OpenSSL::Timestamp::Request.new\n     *      req.algorithm = 'SHA1'\n     *      req.message_imprint = hash\n     *      req.policy_id = \"1.2.3.4.5\"\n     *      req.nonce = 42\n     *      fac = OpenSSL::Timestamp::Factory.new\n     *      fac.gen_time = Time.now\n     *      fac.serial_number = 1\n     *      timestamp = fac.create_timestamp(p12.key, p12.certificate, req)\n     *\n     * ===Verify a timestamp response:\n     *      #Assume we have a timestamp token in a file called ts.der\n     *      ts = OpenSSL::Timestamp::Response.new(File.binread('ts.der'))\n     *      #Assume we have the Request for this token in a file called req.der\n     *      req = OpenSSL::Timestamp::Request.new(File.binread('req.der'))\n     *      # Assume the associated root CA certificate is contained in a\n     *      # DER-encoded file named root.cer\n     *      root = OpenSSL::X509::Certificate.new(File.binread('root.cer'))\n     *      # get the necessary intermediate certificates, available in\n     *      # DER-encoded form in inter1.cer and inter2.cer\n     *      inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer'))\n     *      inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer'))\n     *      ts.verify(req, root, inter1, inter2) -> ts or raises an exception if validation fails\n     *\n     */\n    mTimestamp = rb_define_module_under(mOSSL, \"Timestamp\");\n\n    /* Document-class: OpenSSL::Timestamp::TimestampError\n     * Generic exception class of the Timestamp module.\n     */\n    eTimestampError = rb_define_class_under(mTimestamp, \"TimestampError\", eOSSLError);\n\n    /* Document-class: OpenSSL::Timestamp::Response\n     * Immutable and read-only representation of a timestamp response returned\n     * from a timestamp server after receiving an associated Request. Allows\n     * access to specific information about the response but also allows to\n     * verify the Response.\n     */\n    cTimestampResponse = rb_define_class_under(mTimestamp, \"Response\", rb_cObject);\n    rb_define_alloc_func(cTimestampResponse, ossl_ts_resp_alloc);\n    rb_define_method(cTimestampResponse, \"initialize\", ossl_ts_resp_initialize, 1);\n    rb_define_method(cTimestampResponse, \"status\", ossl_ts_resp_get_status, 0);\n    rb_define_method(cTimestampResponse, \"failure_info\", ossl_ts_resp_get_failure_info, 0);\n    rb_define_method(cTimestampResponse, \"status_text\", ossl_ts_resp_get_status_text, 0);\n    rb_define_method(cTimestampResponse, \"token\", ossl_ts_resp_get_token, 0);\n    rb_define_method(cTimestampResponse, \"token_info\", ossl_ts_resp_get_token_info, 0);\n    rb_define_method(cTimestampResponse, \"tsa_certificate\", ossl_ts_resp_get_tsa_certificate, 0);\n    rb_define_method(cTimestampResponse, \"to_der\", ossl_ts_resp_to_der, 0);\n    rb_define_method(cTimestampResponse, \"to_text\", ossl_ts_resp_to_text, 0);\n    rb_define_method(cTimestampResponse, \"verify\", ossl_ts_resp_verify, -1);\n\n    /* Document-class: OpenSSL::Timestamp::TokenInfo\n     * Immutable and read-only representation of a timestamp token info from a\n     * Response.\n     */\n    cTimestampTokenInfo = rb_define_class_under(mTimestamp, \"TokenInfo\", rb_cObject);\n    rb_define_alloc_func(cTimestampTokenInfo, ossl_ts_token_info_alloc);\n    rb_define_method(cTimestampTokenInfo, \"initialize\", ossl_ts_token_info_initialize, 1);\n    rb_define_method(cTimestampTokenInfo, \"version\", ossl_ts_token_info_get_version, 0);\n    rb_define_method(cTimestampTokenInfo, \"policy_id\", ossl_ts_token_info_get_policy_id, 0);\n    rb_define_method(cTimestampTokenInfo, \"algorithm\", ossl_ts_token_info_get_algorithm, 0);\n    rb_define_method(cTimestampTokenInfo, \"message_imprint\", ossl_ts_token_info_get_msg_imprint, 0);\n    rb_define_method(cTimestampTokenInfo, \"serial_number\", ossl_ts_token_info_get_serial_number, 0);\n    rb_define_method(cTimestampTokenInfo, \"gen_time\", ossl_ts_token_info_get_gen_time, 0);\n    rb_define_method(cTimestampTokenInfo, \"ordering\", ossl_ts_token_info_get_ordering, 0);\n    rb_define_method(cTimestampTokenInfo, \"nonce\", ossl_ts_token_info_get_nonce, 0);\n    rb_define_method(cTimestampTokenInfo, \"to_der\", ossl_ts_token_info_to_der, 0);\n    rb_define_method(cTimestampTokenInfo, \"to_text\", ossl_ts_token_info_to_text, 0);\n\n    /* Document-class: OpenSSL::Timestamp::Request\n     * Allows to create timestamp requests or parse existing ones. A Request is\n     * also needed for creating timestamps from scratch with Factory. When\n     * created from scratch, some default values are set:\n     * * version is set to +1+\n     * * cert_requested is set to +true+\n     * * algorithm, message_imprint, policy_id, and nonce are set to +false+\n     */\n    cTimestampRequest = rb_define_class_under(mTimestamp, \"Request\", rb_cObject);\n    rb_define_alloc_func(cTimestampRequest, ossl_ts_req_alloc);\n    rb_define_method(cTimestampRequest, \"initialize\", ossl_ts_req_initialize, -1);\n    rb_define_method(cTimestampRequest, \"version=\", ossl_ts_req_set_version, 1);\n    rb_define_method(cTimestampRequest, \"version\", ossl_ts_req_get_version, 0);\n    rb_define_method(cTimestampRequest, \"algorithm=\", ossl_ts_req_set_algorithm, 1);\n    rb_define_method(cTimestampRequest, \"algorithm\", ossl_ts_req_get_algorithm, 0);\n    rb_define_method(cTimestampRequest, \"message_imprint=\", ossl_ts_req_set_msg_imprint, 1);\n    rb_define_method(cTimestampRequest, \"message_imprint\", ossl_ts_req_get_msg_imprint, 0);\n    rb_define_method(cTimestampRequest, \"policy_id=\", ossl_ts_req_set_policy_id, 1);\n    rb_define_method(cTimestampRequest, \"policy_id\", ossl_ts_req_get_policy_id, 0);\n    rb_define_method(cTimestampRequest, \"nonce=\", ossl_ts_req_set_nonce, 1);\n    rb_define_method(cTimestampRequest, \"nonce\", ossl_ts_req_get_nonce, 0);\n    rb_define_method(cTimestampRequest, \"cert_requested=\", ossl_ts_req_set_cert_requested, 1);\n    rb_define_method(cTimestampRequest, \"cert_requested?\", ossl_ts_req_get_cert_requested, 0);\n    rb_define_method(cTimestampRequest, \"to_der\", ossl_ts_req_to_der, 0);\n    rb_define_method(cTimestampRequest, \"to_text\", ossl_ts_req_to_text, 0);\n\n    /*\n     * Indicates a successful response. Equal to +0+.\n     */\n    rb_define_const(cTimestampResponse, \"GRANTED\", INT2NUM(TS_STATUS_GRANTED));\n    /*\n     * Indicates a successful response that probably contains modifications\n     * from the initial request. Equal to +1+.\n     */\n    rb_define_const(cTimestampResponse, \"GRANTED_WITH_MODS\", INT2NUM(TS_STATUS_GRANTED_WITH_MODS));\n    /*\n     * Indicates a failure. No timestamp token was created. Equal to +2+.\n     */\n    rb_define_const(cTimestampResponse, \"REJECTION\", INT2NUM(TS_STATUS_REJECTION));\n    /*\n     * Indicates a failure. No timestamp token was created. Equal to +3+.\n     */\n    rb_define_const(cTimestampResponse, \"WAITING\", INT2NUM(TS_STATUS_WAITING));\n    /*\n     * Indicates a failure. No timestamp token was created. Revocation of a\n     * certificate is imminent. Equal to +4+.\n     */\n    rb_define_const(cTimestampResponse, \"REVOCATION_WARNING\", INT2NUM(TS_STATUS_REVOCATION_WARNING));\n    /*\n     * Indicates a failure. No timestamp token was created. A certificate\n     * has been revoked. Equal to +5+.\n     */\n    rb_define_const(cTimestampResponse, \"REVOCATION_NOTIFICATION\", INT2NUM(TS_STATUS_REVOCATION_NOTIFICATION));\n\n    /* Document-class: OpenSSL::Timestamp::Factory\n     *\n     * Used to generate a Response from scratch.\n     *\n     * Please bear in mind that the implementation will always apply and prefer\n     * the policy object identifier given in the request over the default policy\n     * id specified in the Factory. As a consequence, +default_policy_id+ will\n     * only be applied if no Request#policy_id was given. But this also means\n     * that one needs to check the policy identifier in the request manually\n     * before creating the Response, e.g. to check whether it complies to a\n     * specific set of acceptable policies.\n     *\n     * There exists also the possibility to add certificates (instances of\n     * OpenSSL::X509::Certificate) besides the timestamping certificate\n     * that will be included in the resulting timestamp token if\n     * Request#cert_requested? is +true+. Ideally, one would also include any\n     * intermediate certificates (the root certificate can be left out - in\n     * order to trust it any verifying party will have to be in its possession\n     * anyway). This simplifies validation of the timestamp since these\n     * intermediate certificates are \"already there\" and need not be passed as\n     * external parameters to Response#verify anymore, thus minimizing external\n     * resources needed for verification.\n     *\n     * ===Example: Inclusion of (untrusted) intermediate certificates\n     *\n     * Assume we received a timestamp request that has set Request#policy_id to\n     * +nil+ and Request#cert_requested? to true. The raw request bytes are\n     * stored in a variable called +req_raw+. We'd still like to integrate\n     * the necessary intermediate certificates (in +inter1.cer+ and\n     * +inter2.cer+) to simplify validation of the resulting Response. +ts.p12+\n     * is a PKCS#12-compatible file including the private key and the\n     * timestamping certificate.\n     *\n     *      req = OpenSSL::Timestamp::Request.new(raw_bytes)\n     *      p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd')\n     *      inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer'))\n     *      inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer'))\n     *      fac = OpenSSL::Timestamp::Factory.new\n     *      fac.gen_time = Time.now\n     *      fac.serial_number = 1\n     *      fac.allowed_digests = [\"sha256\", \"sha384\", \"sha512\"]\n     *      #needed because the Request contained no policy identifier\n     *      fac.default_policy_id = '1.2.3.4.5'\n     *      fac.additional_certificates = [ inter1, inter2 ]\n     *      timestamp = fac.create_timestamp(p12.key, p12.certificate, req)\n     */\n    cTimestampFactory = rb_define_class_under(mTimestamp, \"Factory\", rb_cObject);\n    /*\n     * The list of digest algorithms that the factory is allowed\n     * create timestamps for. Known vulnerable or weak algorithms should not be\n     * allowed where possible. Must be an Array of String or OpenSSL::Digest\n     * subclass instances.\n     */\n    rb_attr(cTimestampFactory, rb_intern_const(\"allowed_digests\"), 1, 1, 0);\n    /*\n     * A String representing the default policy object identifier, or +nil+.\n     *\n     * Request#policy_id will always be preferred over this if present in the\n     * Request, only if Request#policy_id is +nil+ default_policy will be used.\n     * If none of both is present, a TimestampError will be raised when trying\n     * to create a Response.\n     */\n    rb_attr(cTimestampFactory, rb_intern_const(\"default_policy_id\"), 1, 1, 0);\n    /*\n     * The serial number to be used for timestamp creation. Must be present for\n     * timestamp creation. Must be an instance of OpenSSL::BN or Integer.\n     */\n    rb_attr(cTimestampFactory, rb_intern_const(\"serial_number\"), 1, 1, 0);\n    /*\n     * The Time value to be used in the Response. Must be present for timestamp\n     * creation.\n     */\n    rb_attr(cTimestampFactory, rb_intern_const(\"gen_time\"), 1, 1, 0);\n    /*\n     * Additional certificates apart from the timestamp certificate (e.g.\n     * intermediate certificates) to be added to the Response.\n     * Must be an Array of OpenSSL::X509::Certificate, or +nil+.\n     */\n    rb_attr(cTimestampFactory, rb_intern_const(\"additional_certs\"), 1, 1, 0);\n    rb_define_method(cTimestampFactory, \"create_timestamp\", ossl_tsfac_create_ts, 3);\n}\n#else /* OPENSSL_NO_TS */\nvoid\nInit_ossl_ts(void)\n{\n}\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_ts.h",
    "content": "/*\n *\n * Copyright (C) 2010 Martin Bosslet <Martin.Bosslet@googlemail.com>\n * All rights reserved.\n */\n/*\n * This program is licenced under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n\n#if !defined(_OSSL_TS_H_)\n#define _OSSL_TS_H_\n\nvoid Init_ossl_ts(void);\n\n#endif\n"
  },
  {
    "path": "ext/openssl/ossl_x509.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\nVALUE mX509;\n\n#define DefX509Const(x) rb_define_const(mX509, #x, INT2NUM(X509_##x))\n#define DefX509Default(x,i) \\\n    rb_define_const(mX509, \"DEFAULT_\" #x, \\\n                    rb_obj_freeze(rb_str_new_cstr(X509_get_default_##i())))\n\nASN1_TIME *\nossl_x509_time_adjust(ASN1_TIME *s, VALUE time)\n{\n    time_t sec;\n\n    int off_days;\n\n    ossl_time_split(time, &sec, &off_days);\n    return X509_time_adj_ex(s, off_days, 0, &sec);\n}\n\nvoid\nInit_ossl_x509(void)\n{\n    mX509 = rb_define_module_under(mOSSL, \"X509\");\n\n    Init_ossl_x509attr();\n    Init_ossl_x509cert();\n    Init_ossl_x509crl();\n    Init_ossl_x509ext();\n    Init_ossl_x509name();\n    Init_ossl_x509req();\n    Init_ossl_x509revoked();\n    Init_ossl_x509store();\n\n    /* Constants are up-to-date with 1.1.1. */\n\n    /* Certificate verification error code */\n    DefX509Const(V_OK);\n    DefX509Const(V_ERR_UNSPECIFIED);\n    DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT);\n    DefX509Const(V_ERR_UNABLE_TO_GET_CRL);\n    DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);\n    DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);\n    DefX509Const(V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);\n    DefX509Const(V_ERR_CERT_SIGNATURE_FAILURE);\n    DefX509Const(V_ERR_CRL_SIGNATURE_FAILURE);\n    DefX509Const(V_ERR_CERT_NOT_YET_VALID);\n    DefX509Const(V_ERR_CERT_HAS_EXPIRED);\n    DefX509Const(V_ERR_CRL_NOT_YET_VALID);\n    DefX509Const(V_ERR_CRL_HAS_EXPIRED);\n    DefX509Const(V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);\n    DefX509Const(V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);\n    DefX509Const(V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);\n    DefX509Const(V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);\n    DefX509Const(V_ERR_OUT_OF_MEM);\n    DefX509Const(V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);\n    DefX509Const(V_ERR_SELF_SIGNED_CERT_IN_CHAIN);\n    DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);\n    DefX509Const(V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);\n    DefX509Const(V_ERR_CERT_CHAIN_TOO_LONG);\n    DefX509Const(V_ERR_CERT_REVOKED);\n    DefX509Const(V_ERR_INVALID_CA);\n    DefX509Const(V_ERR_PATH_LENGTH_EXCEEDED);\n    DefX509Const(V_ERR_INVALID_PURPOSE);\n    DefX509Const(V_ERR_CERT_UNTRUSTED);\n    DefX509Const(V_ERR_CERT_REJECTED);\n    DefX509Const(V_ERR_SUBJECT_ISSUER_MISMATCH);\n    DefX509Const(V_ERR_AKID_SKID_MISMATCH);\n    DefX509Const(V_ERR_AKID_ISSUER_SERIAL_MISMATCH);\n    DefX509Const(V_ERR_KEYUSAGE_NO_CERTSIGN);\n    DefX509Const(V_ERR_UNABLE_TO_GET_CRL_ISSUER);\n    DefX509Const(V_ERR_UNHANDLED_CRITICAL_EXTENSION);\n    DefX509Const(V_ERR_KEYUSAGE_NO_CRL_SIGN);\n    DefX509Const(V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION);\n    DefX509Const(V_ERR_INVALID_NON_CA);\n    DefX509Const(V_ERR_PROXY_PATH_LENGTH_EXCEEDED);\n    DefX509Const(V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE);\n    DefX509Const(V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED);\n    DefX509Const(V_ERR_INVALID_EXTENSION);\n    DefX509Const(V_ERR_INVALID_POLICY_EXTENSION);\n    DefX509Const(V_ERR_NO_EXPLICIT_POLICY);\n    DefX509Const(V_ERR_DIFFERENT_CRL_SCOPE);\n    DefX509Const(V_ERR_UNSUPPORTED_EXTENSION_FEATURE);\n    DefX509Const(V_ERR_UNNESTED_RESOURCE);\n    DefX509Const(V_ERR_PERMITTED_VIOLATION);\n    DefX509Const(V_ERR_EXCLUDED_VIOLATION);\n    DefX509Const(V_ERR_SUBTREE_MINMAX);\n    DefX509Const(V_ERR_APPLICATION_VERIFICATION);\n    DefX509Const(V_ERR_UNSUPPORTED_CONSTRAINT_TYPE);\n    DefX509Const(V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX);\n    DefX509Const(V_ERR_UNSUPPORTED_NAME_SYNTAX);\n    DefX509Const(V_ERR_CRL_PATH_VALIDATION_ERROR);\n#if defined(X509_V_ERR_PATH_LOOP) /* OpenSSL 1.1.0, missing in LibreSSL */\n    DefX509Const(V_ERR_PATH_LOOP);\n#endif\n#if defined(X509_V_ERR_SUITE_B_INVALID_VERSION) /* OpenSSL 1.1.0, missing in LibreSSL */\n    DefX509Const(V_ERR_SUITE_B_INVALID_VERSION);\n    DefX509Const(V_ERR_SUITE_B_INVALID_ALGORITHM);\n    DefX509Const(V_ERR_SUITE_B_INVALID_CURVE);\n    DefX509Const(V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM);\n    DefX509Const(V_ERR_SUITE_B_LOS_NOT_ALLOWED);\n    DefX509Const(V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256);\n#endif\n    DefX509Const(V_ERR_HOSTNAME_MISMATCH);\n    DefX509Const(V_ERR_EMAIL_MISMATCH);\n    DefX509Const(V_ERR_IP_ADDRESS_MISMATCH);\n#if defined(X509_V_ERR_DANE_NO_MATCH) /* OpenSSL 1.1.0, missing in LibreSSL */\n    DefX509Const(V_ERR_DANE_NO_MATCH);\n#endif\n    DefX509Const(V_ERR_EE_KEY_TOO_SMALL);\n    DefX509Const(V_ERR_CA_KEY_TOO_SMALL);\n    DefX509Const(V_ERR_CA_MD_TOO_WEAK);\n    DefX509Const(V_ERR_INVALID_CALL);\n    DefX509Const(V_ERR_STORE_LOOKUP);\n#if defined(X509_V_ERR_NO_VALID_SCTS) /* OpenSSL 1.1.0, missing in LibreSSL */\n    DefX509Const(V_ERR_NO_VALID_SCTS);\n#endif\n#if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION) /* OpenSSL 1.1.0, missing in LibreSSL */\n    DefX509Const(V_ERR_PROXY_SUBJECT_NAME_VIOLATION);\n#endif\n#if defined(X509_V_ERR_OCSP_VERIFY_NEEDED) /* OpenSSL 1.1.1, missing in LibreSSL */\n    DefX509Const(V_ERR_OCSP_VERIFY_NEEDED);\n    DefX509Const(V_ERR_OCSP_VERIFY_FAILED);\n    DefX509Const(V_ERR_OCSP_CERT_UNKNOWN);\n#endif\n\n    /* Certificate verify flags */\n    /* Set by Store#flags= and StoreContext#flags=. */\n    DefX509Const(V_FLAG_USE_CHECK_TIME);\n    /* Set by Store#flags= and StoreContext#flags=. Enables CRL checking for the\n     * certificate chain leaf. */\n    DefX509Const(V_FLAG_CRL_CHECK);\n    /* Set by Store#flags= and StoreContext#flags=. Enables CRL checking for all\n     * certificates in the certificate chain */\n    DefX509Const(V_FLAG_CRL_CHECK_ALL);\n    /* Set by Store#flags= and StoreContext#flags=. Disables critical extension\n     * checking. */\n    DefX509Const(V_FLAG_IGNORE_CRITICAL);\n    /* Set by Store#flags= and StoreContext#flags=. Disables workarounds for\n     * broken certificates. */\n    DefX509Const(V_FLAG_X509_STRICT);\n    /* Set by Store#flags= and StoreContext#flags=. Enables proxy certificate\n     * verification. */\n    DefX509Const(V_FLAG_ALLOW_PROXY_CERTS);\n    /* Set by Store#flags= and StoreContext#flags=. Enables certificate policy\n     * constraints checking. */\n    DefX509Const(V_FLAG_POLICY_CHECK);\n    /* Set by Store#flags= and StoreContext#flags=.\n     * Implies V_FLAG_POLICY_CHECK */\n    DefX509Const(V_FLAG_EXPLICIT_POLICY);\n    /* Set by Store#flags= and StoreContext#flags=.\n     * Implies V_FLAG_POLICY_CHECK */\n    DefX509Const(V_FLAG_INHIBIT_ANY);\n    /* Set by Store#flags= and StoreContext#flags=.\n     * Implies V_FLAG_POLICY_CHECK */\n    DefX509Const(V_FLAG_INHIBIT_MAP);\n    /* Set by Store#flags= and StoreContext#flags=. */\n    DefX509Const(V_FLAG_NOTIFY_POLICY);\n    /* Set by Store#flags= and StoreContext#flags=. Enables some additional\n     * features including support for indirect signed CRLs. */\n    DefX509Const(V_FLAG_EXTENDED_CRL_SUPPORT);\n    /* Set by Store#flags= and StoreContext#flags=. Uses delta CRLs. If not\n     * specified, deltas are ignored. */\n    DefX509Const(V_FLAG_USE_DELTAS);\n    /* Set by Store#flags= and StoreContext#flags=. Enables checking of the\n     * signature of the root self-signed CA. */\n    DefX509Const(V_FLAG_CHECK_SS_SIGNATURE);\n    /* Set by Store#flags= and StoreContext#flags=. When constructing a\n     * certificate chain, search the Store first for the issuer certificate.\n     * Enabled by default in OpenSSL >= 1.1.0. */\n    DefX509Const(V_FLAG_TRUSTED_FIRST);\n#if defined(X509_V_FLAG_SUITEB_128_LOS_ONLY) /* OpenSSL 1.1.0, missing in LibreSSL */\n    /* Set by Store#flags= and StoreContext#flags=.\n     * Enables Suite B 128 bit only mode. */\n    DefX509Const(V_FLAG_SUITEB_128_LOS_ONLY);\n    /* Set by Store#flags= and StoreContext#flags=.\n     * Enables Suite B 192 bit only mode. */\n    DefX509Const(V_FLAG_SUITEB_192_LOS);\n    /* Set by Store#flags= and StoreContext#flags=.\n     * Enables Suite B 128 bit mode allowing 192 bit algorithms. */\n    DefX509Const(V_FLAG_SUITEB_128_LOS);\n#endif\n    /* Set by Store#flags= and StoreContext#flags=.\n     * Allows partial chains if at least one certificate is in trusted store. */\n    DefX509Const(V_FLAG_PARTIAL_CHAIN);\n    /* Set by Store#flags= and StoreContext#flags=. Suppresses searching for\n     * a alternative chain. No effect in OpenSSL >= 1.1.0. */\n    DefX509Const(V_FLAG_NO_ALT_CHAINS);\n    /* Set by Store#flags= and StoreContext#flags=. Suppresses checking the\n     * validity period of certificates and CRLs. No effect when the current\n     * time is explicitly set by Store#time= or StoreContext#time=. */\n    DefX509Const(V_FLAG_NO_CHECK_TIME);\n\n    /* Set by Store#purpose=. SSL/TLS client. */\n    DefX509Const(PURPOSE_SSL_CLIENT);\n    /* Set by Store#purpose=. SSL/TLS server. */\n    DefX509Const(PURPOSE_SSL_SERVER);\n    /* Set by Store#purpose=. Netscape SSL server. */\n    DefX509Const(PURPOSE_NS_SSL_SERVER);\n    /* Set by Store#purpose=. S/MIME signing. */\n    DefX509Const(PURPOSE_SMIME_SIGN);\n    /* Set by Store#purpose=. S/MIME encryption. */\n    DefX509Const(PURPOSE_SMIME_ENCRYPT);\n    /* Set by Store#purpose=. CRL signing */\n    DefX509Const(PURPOSE_CRL_SIGN);\n    /* Set by Store#purpose=. No checks. */\n    DefX509Const(PURPOSE_ANY);\n    /* Set by Store#purpose=. OCSP helper. */\n    DefX509Const(PURPOSE_OCSP_HELPER);\n    /* Set by Store#purpose=. Time stamps signer. */\n    DefX509Const(PURPOSE_TIMESTAMP_SIGN);\n\n    DefX509Const(TRUST_COMPAT);\n    DefX509Const(TRUST_SSL_CLIENT);\n    DefX509Const(TRUST_SSL_SERVER);\n    DefX509Const(TRUST_EMAIL);\n    DefX509Const(TRUST_OBJECT_SIGN);\n    DefX509Const(TRUST_OCSP_SIGN);\n    DefX509Const(TRUST_OCSP_REQUEST);\n    DefX509Const(TRUST_TSA);\n\n    DefX509Default(CERT_AREA, cert_area);\n    DefX509Default(CERT_DIR, cert_dir);\n    DefX509Default(CERT_FILE, cert_file);\n    DefX509Default(CERT_DIR_ENV, cert_dir_env);\n    DefX509Default(CERT_FILE_ENV, cert_file_env);\n    DefX509Default(PRIVATE_DIR, private_dir);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_x509.h",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#if !defined(_OSSL_X509_H_)\n#define _OSSL_X509_H_\n\n/*\n * X509 main module\n */\nextern VALUE mX509;\n\n/*\n * Converts the VALUE into Integer and set it to the ASN1_TIME. This is a\n * wrapper for X509_time_adj_ex() so passing NULL creates a new ASN1_TIME.\n * Note that the caller must check the NULL return.\n */\nASN1_TIME *ossl_x509_time_adjust(ASN1_TIME *, VALUE);\n\nvoid Init_ossl_x509(void);\n\n/*\n * X509Attr\n */\nextern VALUE cX509Attr;\n\nVALUE ossl_x509attr_new(const X509_ATTRIBUTE *);\nX509_ATTRIBUTE *GetX509AttrPtr(VALUE);\nvoid Init_ossl_x509attr(void);\n\n/*\n * X509Cert\n */\nextern VALUE cX509Cert;\n\nVALUE ossl_x509_new(const X509 *);\nX509 *GetX509CertPtr(VALUE);\nX509 *DupX509CertPtr(VALUE);\nvoid Init_ossl_x509cert(void);\n\n/*\n * X509CRL\n */\nVALUE ossl_x509crl_new(const X509_CRL *);\nX509_CRL *GetX509CRLPtr(VALUE);\nvoid Init_ossl_x509crl(void);\n\n/*\n * X509Extension\n */\nextern VALUE cX509Ext;\n\nVALUE ossl_x509ext_new(const X509_EXTENSION *);\nX509_EXTENSION *GetX509ExtPtr(VALUE);\nvoid Init_ossl_x509ext(void);\n\n/*\n * X509Name\n */\nVALUE ossl_x509name_new(const X509_NAME *);\nX509_NAME *GetX509NamePtr(VALUE);\nvoid Init_ossl_x509name(void);\n\n/*\n * X509Request\n */\nX509_REQ *GetX509ReqPtr(VALUE);\nvoid Init_ossl_x509req(void);\n\n/*\n * X509Revoked\n */\nextern VALUE cX509Rev;\n\nVALUE ossl_x509revoked_new(const X509_REVOKED *);\nX509_REVOKED *DupX509RevokedPtr(VALUE);\nvoid Init_ossl_x509revoked(void);\n\n/*\n * X509Store and X509StoreContext\n */\nX509_STORE *GetX509StorePtr(VALUE);\nvoid Init_ossl_x509store(void);\n\n/*\n * Calls the verify callback Proc (the first parameter) with given pre-verify\n * result and the X509_STORE_CTX.\n */\nint ossl_verify_cb_call(VALUE, int, X509_STORE_CTX *);\n\n#endif /* _OSSL_X509_H_ */\n"
  },
  {
    "path": "ext/openssl/ossl_x509attr.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewX509Attr(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509attr_type, 0)\n#define SetX509Attr(obj, attr) do { \\\n    if (!(attr)) { \\\n        ossl_raise(rb_eRuntimeError, \"ATTR wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (attr); \\\n} while (0)\n#define GetX509Attr(obj, attr) do { \\\n    TypedData_Get_Struct((obj), X509_ATTRIBUTE, &ossl_x509attr_type, (attr)); \\\n    if (!(attr)) { \\\n        ossl_raise(rb_eRuntimeError, \"ATTR wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nVALUE cX509Attr;\nstatic VALUE eX509AttrError;\n\nstatic void\nossl_x509attr_free(void *ptr)\n{\n    X509_ATTRIBUTE_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_x509attr_type = {\n    \"OpenSSL/X509/ATTRIBUTE\",\n    {\n        0, ossl_x509attr_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Public\n */\nVALUE\nossl_x509attr_new(const X509_ATTRIBUTE *attr)\n{\n    X509_ATTRIBUTE *new;\n    VALUE obj;\n\n    obj = NewX509Attr(cX509Attr);\n    /* OpenSSL 1.1.1 takes a non-const pointer */\n    new = X509_ATTRIBUTE_dup((X509_ATTRIBUTE *)attr);\n    if (!new)\n        ossl_raise(eX509AttrError, \"X509_ATTRIBUTE_dup\");\n    SetX509Attr(obj, new);\n\n    return obj;\n}\n\nX509_ATTRIBUTE *\nGetX509AttrPtr(VALUE obj)\n{\n    X509_ATTRIBUTE *attr;\n\n    GetX509Attr(obj, attr);\n\n    return attr;\n}\n\n/*\n * Private\n */\nstatic VALUE\nossl_x509attr_alloc(VALUE klass)\n{\n    X509_ATTRIBUTE *attr;\n    VALUE obj;\n\n    obj = NewX509Attr(klass);\n    if (!(attr = X509_ATTRIBUTE_new()))\n        ossl_raise(eX509AttrError, NULL);\n    SetX509Attr(obj, attr);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    Attribute.new(oid [, value]) => attr\n */\nstatic VALUE\nossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)\n{\n    VALUE oid, value;\n    X509_ATTRIBUTE *attr, *x;\n    const unsigned char *p;\n\n    GetX509Attr(self, attr);\n    if(rb_scan_args(argc, argv, \"11\", &oid, &value) == 1){\n        oid = ossl_to_der_if_possible(oid);\n        StringValue(oid);\n        p = (unsigned char *)RSTRING_PTR(oid);\n        x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));\n        DATA_PTR(self) = attr;\n        if(!x){\n            ossl_raise(eX509AttrError, NULL);\n        }\n        return self;\n    }\n    rb_funcall(self, rb_intern(\"oid=\"), 1, oid);\n    rb_funcall(self, rb_intern(\"value=\"), 1, value);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_x509attr_initialize_copy(VALUE self, VALUE other)\n{\n    X509_ATTRIBUTE *attr, *attr_other, *attr_new;\n\n    rb_check_frozen(self);\n    GetX509Attr(self, attr);\n    GetX509Attr(other, attr_other);\n\n    attr_new = X509_ATTRIBUTE_dup(attr_other);\n    if (!attr_new)\n        ossl_raise(eX509AttrError, \"X509_ATTRIBUTE_dup\");\n\n    SetX509Attr(self, attr_new);\n    X509_ATTRIBUTE_free(attr);\n\n    return self;\n}\n\n/*\n * call-seq:\n *    attr.oid = string => string\n */\nstatic VALUE\nossl_x509attr_set_oid(VALUE self, VALUE oid)\n{\n    X509_ATTRIBUTE *attr;\n    ASN1_OBJECT *obj;\n    char *s;\n\n    GetX509Attr(self, attr);\n    s = StringValueCStr(oid);\n    obj = OBJ_txt2obj(s, 0);\n    if(!obj) ossl_raise(eX509AttrError, NULL);\n    if (!X509_ATTRIBUTE_set1_object(attr, obj)) {\n        ASN1_OBJECT_free(obj);\n        ossl_raise(eX509AttrError, \"X509_ATTRIBUTE_set1_object\");\n    }\n    ASN1_OBJECT_free(obj);\n\n    return oid;\n}\n\n/*\n * call-seq:\n *    attr.oid -> string\n *\n * Returns the OID of the attribute. Returns the short name or the dotted\n * decimal notation.\n */\nstatic VALUE\nossl_x509attr_get_oid(VALUE self)\n{\n    X509_ATTRIBUTE *attr;\n\n    GetX509Attr(self, attr);\n    return ossl_asn1obj_to_string(X509_ATTRIBUTE_get0_object(attr));\n}\n\n/*\n * call-seq:\n *    attr.value = asn1 => asn1\n */\nstatic VALUE\nossl_x509attr_set_value(VALUE self, VALUE value)\n{\n    X509_ATTRIBUTE *attr;\n    GetX509Attr(self, attr);\n\n    OSSL_Check_Kind(value, cASN1Data);\n    VALUE der = ossl_to_der(value);\n    const unsigned char *p = (const unsigned char *)RSTRING_PTR(der);\n    STACK_OF(ASN1_TYPE) *sk = d2i_ASN1_SET_ANY(NULL, &p, RSTRING_LEN(der));\n    if (!sk)\n        ossl_raise(eX509AttrError, \"attribute value must be ASN1::Set\");\n\n    if (X509_ATTRIBUTE_count(attr)) { /* populated, reset first */\n        const ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr);\n        X509_ATTRIBUTE *new_attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, 0, NULL, -1);\n        if (!new_attr) {\n            sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);\n            ossl_raise(eX509AttrError, \"X509_ATTRIBUTE_create_by_OBJ\");\n        }\n        SetX509Attr(self, new_attr);\n        X509_ATTRIBUTE_free(attr);\n        attr = new_attr;\n    }\n\n    for (int i = 0; i < sk_ASN1_TYPE_num(sk); i++) {\n        ASN1_TYPE *a1type = sk_ASN1_TYPE_value(sk, i);\n        if (!X509_ATTRIBUTE_set1_data(attr, ASN1_TYPE_get(a1type),\n                                      a1type->value.ptr, -1)) {\n            sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);\n            ossl_raise(eX509AttrError, \"X509_ATTRIBUTE_set1_data\");\n        }\n    }\n    sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);\n\n    return value;\n}\n\n/*\n * call-seq:\n *    attr.value => asn1\n */\nstatic VALUE\nossl_x509attr_get_value(VALUE self)\n{\n    X509_ATTRIBUTE *attr;\n    STACK_OF(ASN1_TYPE) *sk;\n    VALUE str;\n    int i, count, len;\n    unsigned char *p;\n\n    GetX509Attr(self, attr);\n    /* there is no X509_ATTRIBUTE_get0_set() :( */\n    if (!(sk = sk_ASN1_TYPE_new_null()))\n        ossl_raise(eX509AttrError, \"sk_new\");\n\n    count = X509_ATTRIBUTE_count(attr);\n    for (i = 0; i < count; i++)\n        sk_ASN1_TYPE_push(sk, (ASN1_TYPE *)X509_ATTRIBUTE_get0_type(attr, i));\n\n    if ((len = i2d_ASN1_SET_ANY(sk, NULL)) <= 0) {\n        sk_ASN1_TYPE_free(sk);\n        ossl_raise(eX509AttrError, NULL);\n    }\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_ASN1_SET_ANY(sk, &p) <= 0) {\n        sk_ASN1_TYPE_free(sk);\n        ossl_raise(eX509AttrError, NULL);\n    }\n    ossl_str_adjust(str, p);\n    sk_ASN1_TYPE_free(sk);\n\n    return rb_funcall(mASN1, rb_intern(\"decode\"), 1, str);\n}\n\n/*\n * call-seq:\n *    attr.to_der => string\n */\nstatic VALUE\nossl_x509attr_to_der(VALUE self)\n{\n    X509_ATTRIBUTE *attr;\n    VALUE str;\n    int len;\n    unsigned char *p;\n\n    GetX509Attr(self, attr);\n    if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0)\n        ossl_raise(eX509AttrError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d_X509_ATTRIBUTE(attr, &p) <= 0)\n        ossl_raise(eX509AttrError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * X509_ATTRIBUTE init\n */\nvoid\nInit_ossl_x509attr(void)\n{\n    eX509AttrError = rb_define_class_under(mX509, \"AttributeError\", eOSSLError);\n\n    cX509Attr = rb_define_class_under(mX509, \"Attribute\", rb_cObject);\n    rb_define_alloc_func(cX509Attr, ossl_x509attr_alloc);\n    rb_define_method(cX509Attr, \"initialize\", ossl_x509attr_initialize, -1);\n    rb_define_method(cX509Attr, \"initialize_copy\", ossl_x509attr_initialize_copy, 1);\n    rb_define_method(cX509Attr, \"oid=\", ossl_x509attr_set_oid, 1);\n    rb_define_method(cX509Attr, \"oid\", ossl_x509attr_get_oid, 0);\n    rb_define_method(cX509Attr, \"value=\", ossl_x509attr_set_value, 1);\n    rb_define_method(cX509Attr, \"value\", ossl_x509attr_get_value, 0);\n    rb_define_method(cX509Attr, \"to_der\", ossl_x509attr_to_der, 0);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_x509cert.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewX509(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509_type, 0)\n#define SetX509(obj, x509) do { \\\n    if (!(x509)) { \\\n        ossl_raise(rb_eRuntimeError, \"CERT wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (x509); \\\n} while (0)\n#define GetX509(obj, x509) do { \\\n    TypedData_Get_Struct((obj), X509, &ossl_x509_type, (x509)); \\\n    if (!(x509)) { \\\n        ossl_raise(rb_eRuntimeError, \"CERT wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nVALUE cX509Cert;\nstatic VALUE eX509CertError;\n\nstatic void\nossl_x509_free(void *ptr)\n{\n    X509_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_x509_type = {\n    \"OpenSSL/X509\",\n    {\n        0, ossl_x509_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Public\n */\nVALUE\nossl_x509_new(const X509 *x509)\n{\n    X509 *new;\n    VALUE obj;\n\n    obj = NewX509(cX509Cert);\n    /* OpenSSL 1.1.1 takes a non-const pointer */\n    new = X509_dup((X509 *)x509);\n    if (!new)\n        ossl_raise(eX509CertError, \"X509_dup\");\n    SetX509(obj, new);\n\n    return obj;\n}\n\nX509 *\nGetX509CertPtr(VALUE obj)\n{\n    X509 *x509;\n\n    GetX509(obj, x509);\n\n    return x509;\n}\n\nX509 *\nDupX509CertPtr(VALUE obj)\n{\n    X509 *x509;\n\n    GetX509(obj, x509);\n\n    X509_up_ref(x509);\n\n    return x509;\n}\n\n/*\n * Private\n */\nstatic VALUE\nossl_x509_alloc(VALUE klass)\n{\n    X509 *x509;\n    VALUE obj;\n\n    obj = NewX509(klass);\n    x509 = X509_new();\n    if (!x509) ossl_raise(eX509CertError, NULL);\n    SetX509(obj, x509);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    Certificate.new => cert\n *    Certificate.new(string) => cert\n */\nstatic VALUE\nossl_x509_initialize(int argc, VALUE *argv, VALUE self)\n{\n    BIO *in;\n    X509 *x509, *x509_orig = RTYPEDDATA_DATA(self);\n    VALUE arg;\n\n    rb_check_frozen(self);\n    if (rb_scan_args(argc, argv, \"01\", &arg) == 0) {\n        /* create just empty X509Cert */\n        return self;\n    }\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n    x509 = d2i_X509_bio(in, NULL);\n    if (!x509) {\n        OSSL_BIO_reset(in);\n        x509 = PEM_read_bio_X509(in, NULL, NULL, NULL);\n    }\n    BIO_free(in);\n    if (!x509)\n        ossl_raise(eX509CertError, \"PEM_read_bio_X509\");\n\n    RTYPEDDATA_DATA(self) = x509;\n    X509_free(x509_orig);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_x509_copy(VALUE self, VALUE other)\n{\n    X509 *a, *b, *x509;\n\n    rb_check_frozen(self);\n    if (self == other) return self;\n\n    GetX509(self, a);\n    GetX509(other, b);\n\n    x509 = X509_dup(b);\n    if (!x509) ossl_raise(eX509CertError, NULL);\n\n    DATA_PTR(self) = x509;\n    X509_free(a);\n\n    return self;\n}\n\n/*\n * call-seq:\n *    cert.to_der => string\n */\nstatic VALUE\nossl_x509_to_der(VALUE self)\n{\n    X509 *x509;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetX509(self, x509);\n    if ((len = i2d_X509(x509, NULL)) <= 0)\n        ossl_raise(eX509CertError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_X509(x509, &p) <= 0)\n        ossl_raise(eX509CertError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * call-seq:\n *    cert.to_pem => string\n */\nstatic VALUE\nossl_x509_to_pem(VALUE self)\n{\n    X509 *x509;\n    BIO *out;\n    VALUE str;\n\n    GetX509(self, x509);\n    out = BIO_new(BIO_s_mem());\n    if (!out) ossl_raise(eX509CertError, NULL);\n\n    if (!PEM_write_bio_X509(out, x509)) {\n        BIO_free(out);\n        ossl_raise(eX509CertError, NULL);\n    }\n    str = ossl_membio2str(out);\n\n    return str;\n}\n\n/*\n * call-seq:\n *    cert.to_text => string\n */\nstatic VALUE\nossl_x509_to_text(VALUE self)\n{\n    X509 *x509;\n    BIO *out;\n    VALUE str;\n\n    GetX509(self, x509);\n\n    out = BIO_new(BIO_s_mem());\n    if (!out) ossl_raise(eX509CertError, NULL);\n\n    if (!X509_print(out, x509)) {\n        BIO_free(out);\n        ossl_raise(eX509CertError, NULL);\n    }\n    str = ossl_membio2str(out);\n\n    return str;\n}\n\n#if 0\n/*\n * Makes from X509 X509_REQuest\n */\nstatic VALUE\nossl_x509_to_req(VALUE self)\n{\n    X509 *x509;\n    X509_REQ *req;\n    VALUE obj;\n\n    GetX509(self, x509);\n    if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) {\n        ossl_raise(eX509CertError, NULL);\n    }\n    obj = ossl_x509req_new(req);\n    X509_REQ_free(req);\n\n    return obj;\n}\n#endif\n\n/*\n * call-seq:\n *    cert.version => integer\n */\nstatic VALUE\nossl_x509_get_version(VALUE self)\n{\n    X509 *x509;\n\n    GetX509(self, x509);\n\n    return LONG2NUM(X509_get_version(x509));\n}\n\n/*\n * call-seq:\n *    cert.version = integer => integer\n */\nstatic VALUE\nossl_x509_set_version(VALUE self, VALUE version)\n{\n    X509 *x509;\n    long ver;\n\n    if ((ver = NUM2LONG(version)) < 0) {\n        ossl_raise(eX509CertError, \"version must be >= 0!\");\n    }\n    GetX509(self, x509);\n    if (!X509_set_version(x509, ver)) {\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return version;\n}\n\n/*\n * call-seq:\n *    cert.serial => integer\n */\nstatic VALUE\nossl_x509_get_serial(VALUE self)\n{\n    X509 *x509;\n\n    GetX509(self, x509);\n\n    return asn1integer_to_num(X509_get_serialNumber(x509));\n}\n\n/*\n * call-seq:\n *    cert.serial = integer => integer\n */\nstatic VALUE\nossl_x509_set_serial(VALUE self, VALUE num)\n{\n    X509 *x509;\n\n    GetX509(self, x509);\n    if (!X509_set_serialNumber(x509, num_to_asn1integer(num, X509_get_serialNumber(x509)))) {\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return num;\n}\n\n/*\n * call-seq:\n *    cert.signature_algorithm => string\n *\n * Returns the signature algorithm used to sign this certificate. This returns\n * the algorithm name found in the TBSCertificate structure, not the outer\n * \\Certificate structure.\n *\n * Returns the long name of the signature algorithm, or the dotted decimal\n * notation if \\OpenSSL does not define a long name for it.\n */\nstatic VALUE\nossl_x509_get_signature_algorithm(VALUE self)\n{\n    X509 *x509;\n    const ASN1_OBJECT *obj;\n\n    GetX509(self, x509);\n    X509_ALGOR_get0(&obj, NULL, NULL, X509_get0_tbs_sigalg(x509));\n    return ossl_asn1obj_to_string_long_name(obj);\n}\n\n/*\n * call-seq:\n *    cert.subject => name\n */\nstatic VALUE\nossl_x509_get_subject(VALUE self)\n{\n    X509 *x509;\n    const X509_NAME *name;\n\n    GetX509(self, x509);\n    if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return ossl_x509name_new(name);\n}\n\n/*\n * call-seq:\n *    cert.subject = name => name\n */\nstatic VALUE\nossl_x509_set_subject(VALUE self, VALUE subject)\n{\n    X509 *x509;\n\n    GetX509(self, x509);\n    if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return subject;\n}\n\n/*\n * call-seq:\n *    cert.issuer => name\n */\nstatic VALUE\nossl_x509_get_issuer(VALUE self)\n{\n    X509 *x509;\n    const X509_NAME *name;\n\n    GetX509(self, x509);\n    if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return ossl_x509name_new(name);\n}\n\n/*\n * call-seq:\n *    cert.issuer = name => name\n */\nstatic VALUE\nossl_x509_set_issuer(VALUE self, VALUE issuer)\n{\n    X509 *x509;\n\n    GetX509(self, x509);\n    if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return issuer;\n}\n\n/*\n * call-seq:\n *    cert.not_before => time\n */\nstatic VALUE\nossl_x509_get_not_before(VALUE self)\n{\n    X509 *x509;\n    const ASN1_TIME *asn1time;\n\n    GetX509(self, x509);\n    if (!(asn1time = X509_get0_notBefore(x509))) {\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return asn1time_to_time(asn1time);\n}\n\n/*\n * call-seq:\n *    cert.not_before = time => time\n */\nstatic VALUE\nossl_x509_set_not_before(VALUE self, VALUE time)\n{\n    X509 *x509;\n    ASN1_TIME *asn1time;\n\n    GetX509(self, x509);\n    asn1time = ossl_x509_time_adjust(NULL, time);\n    if (!X509_set1_notBefore(x509, asn1time)) {\n        ASN1_TIME_free(asn1time);\n        ossl_raise(eX509CertError, \"X509_set_notBefore\");\n    }\n    ASN1_TIME_free(asn1time);\n\n    return time;\n}\n\n/*\n * call-seq:\n *    cert.not_after => time\n */\nstatic VALUE\nossl_x509_get_not_after(VALUE self)\n{\n    X509 *x509;\n    const ASN1_TIME *asn1time;\n\n    GetX509(self, x509);\n    if (!(asn1time = X509_get0_notAfter(x509))) {\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return asn1time_to_time(asn1time);\n}\n\n/*\n * call-seq:\n *    cert.not_after = time => time\n */\nstatic VALUE\nossl_x509_set_not_after(VALUE self, VALUE time)\n{\n    X509 *x509;\n    ASN1_TIME *asn1time;\n\n    GetX509(self, x509);\n    asn1time = ossl_x509_time_adjust(NULL, time);\n    if (!X509_set1_notAfter(x509, asn1time)) {\n        ASN1_TIME_free(asn1time);\n        ossl_raise(eX509CertError, \"X509_set_notAfter\");\n    }\n    ASN1_TIME_free(asn1time);\n\n    return time;\n}\n\n/*\n * call-seq:\n *    cert.public_key => key\n */\nstatic VALUE\nossl_x509_get_public_key(VALUE self)\n{\n    X509 *x509;\n    EVP_PKEY *pkey;\n\n    GetX509(self, x509);\n    if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return ossl_pkey_wrap(pkey);\n}\n\n/*\n * call-seq:\n *    cert.public_key = key\n */\nstatic VALUE\nossl_x509_set_public_key(VALUE self, VALUE key)\n{\n    X509 *x509;\n    EVP_PKEY *pkey;\n\n    GetX509(self, x509);\n    pkey = GetPKeyPtr(key);\n    ossl_pkey_check_public_key(pkey);\n    if (!X509_set_pubkey(x509, pkey))\n        ossl_raise(eX509CertError, \"X509_set_pubkey\");\n    return key;\n}\n\n/*\n * call-seq:\n *    cert.sign(key, digest) => self\n */\nstatic VALUE\nossl_x509_sign(VALUE self, VALUE key, VALUE digest)\n{\n    X509 *x509;\n    EVP_PKEY *pkey;\n    const EVP_MD *md;\n    VALUE md_holder;\n\n    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */\n    /* NULL needed for some key types, e.g. Ed25519 */\n    md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);\n    GetX509(self, x509);\n    if (!X509_sign(x509, pkey, md))\n        ossl_raise(eX509CertError, \"X509_sign\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *    cert.verify(key) => true | false\n *\n * Verifies the signature of the certificate, with the public key _key_. _key_\n * must be an instance of OpenSSL::PKey.\n */\nstatic VALUE\nossl_x509_verify(VALUE self, VALUE key)\n{\n    X509 *x509;\n    EVP_PKEY *pkey;\n\n    GetX509(self, x509);\n    pkey = GetPKeyPtr(key);\n    ossl_pkey_check_public_key(pkey);\n    switch (X509_verify(x509, pkey)) {\n      case 1:\n        return Qtrue;\n      case 0:\n        ossl_clear_error();\n        return Qfalse;\n      default:\n        ossl_raise(eX509CertError, NULL);\n    }\n}\n\n/*\n * call-seq:\n *    cert.check_private_key(key) -> true | false\n *\n * Returns +true+ if _key_ is the corresponding private key to the Subject\n * Public Key Information, +false+ otherwise.\n */\nstatic VALUE\nossl_x509_check_private_key(VALUE self, VALUE key)\n{\n    X509 *x509;\n    EVP_PKEY *pkey;\n\n    /* not needed private key, but should be */\n    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */\n    GetX509(self, x509);\n    if (!X509_check_private_key(x509, pkey)) {\n        ossl_clear_error();\n        return Qfalse;\n    }\n\n    return Qtrue;\n}\n\n/*\n * call-seq:\n *    cert.extensions => [extension...]\n */\nstatic VALUE\nossl_x509_get_extensions(VALUE self)\n{\n    X509 *x509;\n    int count, i;\n    VALUE ary;\n\n    GetX509(self, x509);\n    count = X509_get_ext_count(x509);\n    ary = rb_ary_new_capa(count);\n    for (i=0; i<count; i++) {\n        const X509_EXTENSION *ext = X509_get_ext(x509, i);\n        rb_ary_push(ary, ossl_x509ext_new(ext));\n    }\n\n    return ary;\n}\n\n/*\n * call-seq:\n *    cert.extensions = [ext...] => [ext...]\n */\nstatic VALUE\nossl_x509_set_extensions(VALUE self, VALUE ary)\n{\n    X509 *x509;\n    X509_EXTENSION *ext;\n    long i;\n\n    Check_Type(ary, T_ARRAY);\n    /* All ary's members should be X509Extension */\n    for (i=0; i<RARRAY_LEN(ary); i++) {\n        OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);\n    }\n    GetX509(self, x509);\n    for (i = X509_get_ext_count(x509); i > 0; i--)\n        X509_EXTENSION_free(X509_delete_ext(x509, 0));\n    for (i=0; i<RARRAY_LEN(ary); i++) {\n        ext = GetX509ExtPtr(RARRAY_AREF(ary, i));\n        if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext */\n            ossl_raise(eX509CertError, \"X509_add_ext\");\n        }\n    }\n\n    return ary;\n}\n\n/*\n * call-seq:\n *    cert.add_extension(extension) => extension\n */\nstatic VALUE\nossl_x509_add_extension(VALUE self, VALUE extension)\n{\n    X509 *x509;\n    X509_EXTENSION *ext;\n\n    GetX509(self, x509);\n    ext = GetX509ExtPtr(extension);\n    if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */\n        ossl_raise(eX509CertError, NULL);\n    }\n\n    return extension;\n}\n\n/*\n * call-seq:\n *    cert1 == cert2 -> true | false\n *\n * Compares the two certificates. Note that this takes into account all fields,\n * not just the issuer name and the serial number.\n *\n * This method uses X509_cmp() from OpenSSL, which compares certificates based\n * on their cached DER encodings. The comparison can be unreliable if a\n * certificate is incomplete.\n *\n * See also the man page X509_cmp(3).\n */\nstatic VALUE\nossl_x509_eq(VALUE self, VALUE other)\n{\n    X509 *a, *b;\n\n    GetX509(self, a);\n    if (!rb_obj_is_kind_of(other, cX509Cert))\n        return Qfalse;\n    GetX509(other, b);\n\n    return !X509_cmp(a, b) ? Qtrue : Qfalse;\n}\n\n/*\n * call-seq:\n *    cert.tbs_bytes => string\n *\n * Returns the DER-encoded bytes of the certificate's to be signed certificate.\n * This is mainly useful for validating embedded certificate transparency signatures.\n */\nstatic VALUE\nossl_x509_tbs_bytes(VALUE self)\n{\n    X509 *x509;\n    int len;\n    unsigned char *p0;\n    VALUE str;\n\n    GetX509(self, x509);\n    len = i2d_re_X509_tbs(x509, NULL);\n    if (len <= 0) {\n        ossl_raise(eX509CertError, \"i2d_re_X509_tbs\");\n    }\n    str = rb_str_new(NULL, len);\n    p0 = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_re_X509_tbs(x509, &p0) <= 0) {\n        ossl_raise(eX509CertError, \"i2d_re_X509_tbs\");\n    }\n    ossl_str_adjust(str, p0);\n\n    return str;\n}\n\nstruct load_chained_certificates_arguments {\n    VALUE certificates;\n    X509 *certificate;\n};\n\nstatic VALUE\nload_chained_certificates_append_push(VALUE _arguments) {\n    struct load_chained_certificates_arguments *arguments = (struct load_chained_certificates_arguments*)_arguments;\n\n    if (arguments->certificates == Qnil) {\n        arguments->certificates = rb_ary_new();\n    }\n\n    rb_ary_push(arguments->certificates, ossl_x509_new(arguments->certificate));\n\n    return Qnil;\n}\n\nstatic VALUE\nload_chained_certificate_append_ensure(VALUE _arguments) {\n    struct load_chained_certificates_arguments *arguments = (struct load_chained_certificates_arguments*)_arguments;\n\n    X509_free(arguments->certificate);\n\n    return Qnil;\n}\n\ninline static VALUE\nload_chained_certificates_append(VALUE certificates, X509 *certificate) {\n    struct load_chained_certificates_arguments arguments;\n    arguments.certificates = certificates;\n    arguments.certificate = certificate;\n\n    rb_ensure(load_chained_certificates_append_push, (VALUE)&arguments, load_chained_certificate_append_ensure, (VALUE)&arguments);\n\n    return arguments.certificates;\n}\n\nstatic VALUE\nload_chained_certificates_PEM(BIO *in) {\n    VALUE certificates = Qnil;\n    X509 *certificate = PEM_read_bio_X509(in, NULL, NULL, NULL);\n\n    /* If we cannot read even one certificate: */\n    if (certificate == NULL) {\n        /* If we cannot read one certificate because we could not read the PEM encoding: */\n        if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {\n            ossl_clear_error();\n        }\n\n        if (ERR_peek_last_error())\n            ossl_raise(eX509CertError, NULL);\n        else\n            return Qnil;\n    }\n\n    certificates = load_chained_certificates_append(Qnil, certificate);\n\n    while ((certificate = PEM_read_bio_X509(in, NULL, NULL, NULL))) {\n        load_chained_certificates_append(certificates, certificate);\n    }\n\n    /* We tried to read one more certificate but could not read start line: */\n    if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {\n        /* This is not an error, it means we are finished: */\n        ossl_clear_error();\n\n        return certificates;\n    }\n\n    /* Alternatively, if we reached the end of the file and there was no error: */\n    if (BIO_eof(in) && !ERR_peek_last_error()) {\n        return certificates;\n    } else {\n        /* Otherwise, we tried to read a certificate but failed somewhere: */\n        ossl_raise(eX509CertError, NULL);\n    }\n}\n\nstatic VALUE\nload_chained_certificates_DER(BIO *in) {\n    X509 *certificate = d2i_X509_bio(in, NULL);\n\n    /* If we cannot read one certificate: */\n    if (certificate == NULL) {\n        /* Ignore error. We could not load. */\n        ossl_clear_error();\n\n        return Qnil;\n    }\n\n    return load_chained_certificates_append(Qnil, certificate);\n}\n\nstatic VALUE\nload_chained_certificates(VALUE _io) {\n    BIO *in = (BIO*)_io;\n    VALUE certificates = Qnil;\n\n    /*\n      DER is a binary format and it may contain octets within it that look like\n      PEM encoded certificates. So we need to check DER first.\n    */\n    certificates = load_chained_certificates_DER(in);\n\n    if (certificates != Qnil)\n        return certificates;\n\n    OSSL_BIO_reset(in);\n\n    certificates = load_chained_certificates_PEM(in);\n\n    if (certificates != Qnil)\n        return certificates;\n\n    /* Otherwise we couldn't read the output correctly so fail: */\n    ossl_raise(eX509CertError, \"Could not detect format of certificate data!\");\n}\n\nstatic VALUE\nload_chained_certificates_ensure(VALUE _io) {\n    BIO *in = (BIO*)_io;\n\n    BIO_free(in);\n\n    return Qnil;\n}\n\n/*\n * call-seq:\n *    OpenSSL::X509::Certificate.load(string) -> [certs...]\n *    OpenSSL::X509::Certificate.load(file) -> [certs...]\n *\n * Read the chained certificates from the given input. Supports both PEM\n * and DER encoded certificates.\n *\n * PEM is a text format and supports more than one certificate.\n *\n * DER is a binary format and only supports one certificate.\n *\n * If the file is empty, or contains only unrelated data, an\n * +OpenSSL::X509::CertificateError+ exception will be raised.\n */\nstatic VALUE\nossl_x509_load(VALUE klass, VALUE buffer)\n{\n    BIO *in = ossl_obj2bio(&buffer);\n\n    return rb_ensure(load_chained_certificates, (VALUE)in, load_chained_certificates_ensure, (VALUE)in);\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_x509cert(void)\n{\n    eX509CertError = rb_define_class_under(mX509, \"CertificateError\", eOSSLError);\n\n    /* Document-class: OpenSSL::X509::Certificate\n     *\n     * Implementation of an X.509 certificate as specified in RFC 5280.\n     * Provides access to a certificate's attributes and allows certificates\n     * to be read from a string, but also supports the creation of new\n     * certificates from scratch.\n     *\n     * === Reading a certificate from a file\n     *\n     * Certificate is capable of handling DER-encoded certificates and\n     * certificates encoded in OpenSSL's PEM format.\n     *\n     *   raw = File.binread \"cert.cer\" # DER- or PEM-encoded\n     *   certificate = OpenSSL::X509::Certificate.new raw\n     *\n     * === Saving a certificate to a file\n     *\n     * A certificate may be encoded in DER format\n     *\n     *   cert = ...\n     *   File.open(\"cert.cer\", \"wb\") { |f| f.print cert.to_der }\n     *\n     * or in PEM format\n     *\n     *   cert = ...\n     *   File.open(\"cert.pem\", \"wb\") { |f| f.print cert.to_pem }\n     *\n     * X.509 certificates are associated with a private/public key pair,\n     * typically a RSA, DSA or ECC key (see also OpenSSL::PKey::RSA,\n     * OpenSSL::PKey::DSA and OpenSSL::PKey::EC), the public key itself is\n     * stored within the certificate and can be accessed in form of an\n     * OpenSSL::PKey. Certificates are typically used to be able to associate\n     * some form of identity with a key pair, for example web servers serving\n     * pages over HTTPs use certificates to authenticate themselves to the user.\n     *\n     * The public key infrastructure (PKI) model relies on trusted certificate\n     * authorities (\"root CAs\") that issue these certificates, so that end\n     * users need to base their trust just on a selected few authorities\n     * that themselves again vouch for subordinate CAs issuing their\n     * certificates to end users.\n     *\n     * The OpenSSL::X509 module provides the tools to set up an independent\n     * PKI, similar to scenarios where the 'openssl' command line tool is\n     * used for issuing certificates in a private PKI.\n     *\n     * === Creating a root CA certificate and an end-entity certificate\n     *\n     * First, we need to create a \"self-signed\" root certificate. To do so,\n     * we need to generate a key first. Please note that the choice of \"1\"\n     * as a serial number is considered a security flaw for real certificates.\n     * Secure choices are integers in the two-digit byte range and ideally\n     * not sequential but secure random numbers, steps omitted here to keep\n     * the example concise.\n     *\n     *   root_key = OpenSSL::PKey::RSA.new 2048 # the CA's public/private key\n     *   root_ca = OpenSSL::X509::Certificate.new\n     *   root_ca.version = 2 # cf. RFC 5280 - to make it a \"v3\" certificate\n     *   root_ca.serial = 1\n     *   root_ca.subject = OpenSSL::X509::Name.parse \"/DC=org/DC=ruby-lang/CN=Ruby CA\"\n     *   root_ca.issuer = root_ca.subject # root CA's are \"self-signed\"\n     *   root_ca.public_key = root_key.public_key\n     *   root_ca.not_before = Time.now\n     *   root_ca.not_after = root_ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity\n     *   ef = OpenSSL::X509::ExtensionFactory.new\n     *   ef.subject_certificate = root_ca\n     *   ef.issuer_certificate = root_ca\n     *   root_ca.add_extension(ef.create_extension(\"basicConstraints\",\"CA:TRUE\",true))\n     *   root_ca.add_extension(ef.create_extension(\"keyUsage\",\"keyCertSign, cRLSign\", true))\n     *   root_ca.add_extension(ef.create_extension(\"subjectKeyIdentifier\",\"hash\",false))\n     *   root_ca.add_extension(ef.create_extension(\"authorityKeyIdentifier\",\"keyid:always\",false))\n     *   root_ca.sign(root_key, OpenSSL::Digest.new('SHA256'))\n     *\n     * The next step is to create the end-entity certificate using the root CA\n     * certificate.\n     *\n     *   key = OpenSSL::PKey::RSA.new 2048\n     *   cert = OpenSSL::X509::Certificate.new\n     *   cert.version = 2\n     *   cert.serial = 2\n     *   cert.subject = OpenSSL::X509::Name.parse \"/DC=org/DC=ruby-lang/CN=Ruby certificate\"\n     *   cert.issuer = root_ca.subject # root CA is the issuer\n     *   cert.public_key = key.public_key\n     *   cert.not_before = Time.now\n     *   cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60 # 1 years validity\n     *   ef = OpenSSL::X509::ExtensionFactory.new\n     *   ef.subject_certificate = cert\n     *   ef.issuer_certificate = root_ca\n     *   cert.add_extension(ef.create_extension(\"keyUsage\",\"digitalSignature\", true))\n     *   cert.add_extension(ef.create_extension(\"subjectKeyIdentifier\",\"hash\",false))\n     *   cert.sign(root_key, OpenSSL::Digest.new('SHA256'))\n     *\n     */\n    cX509Cert = rb_define_class_under(mX509, \"Certificate\", rb_cObject);\n\n    rb_define_singleton_method(cX509Cert, \"load\", ossl_x509_load, 1);\n\n    rb_define_alloc_func(cX509Cert, ossl_x509_alloc);\n    rb_define_method(cX509Cert, \"initialize\", ossl_x509_initialize, -1);\n    rb_define_method(cX509Cert, \"initialize_copy\", ossl_x509_copy, 1);\n\n    rb_define_method(cX509Cert, \"to_der\", ossl_x509_to_der, 0);\n    rb_define_method(cX509Cert, \"to_pem\", ossl_x509_to_pem, 0);\n    rb_define_alias(cX509Cert, \"to_s\", \"to_pem\");\n    rb_define_method(cX509Cert, \"to_text\", ossl_x509_to_text, 0);\n    rb_define_method(cX509Cert, \"version\", ossl_x509_get_version, 0);\n    rb_define_method(cX509Cert, \"version=\", ossl_x509_set_version, 1);\n    rb_define_method(cX509Cert, \"signature_algorithm\", ossl_x509_get_signature_algorithm, 0);\n    rb_define_method(cX509Cert, \"serial\", ossl_x509_get_serial, 0);\n    rb_define_method(cX509Cert, \"serial=\", ossl_x509_set_serial, 1);\n    rb_define_method(cX509Cert, \"subject\", ossl_x509_get_subject, 0);\n    rb_define_method(cX509Cert, \"subject=\", ossl_x509_set_subject, 1);\n    rb_define_method(cX509Cert, \"issuer\", ossl_x509_get_issuer, 0);\n    rb_define_method(cX509Cert, \"issuer=\", ossl_x509_set_issuer, 1);\n    rb_define_method(cX509Cert, \"not_before\", ossl_x509_get_not_before, 0);\n    rb_define_method(cX509Cert, \"not_before=\", ossl_x509_set_not_before, 1);\n    rb_define_method(cX509Cert, \"not_after\", ossl_x509_get_not_after, 0);\n    rb_define_method(cX509Cert, \"not_after=\", ossl_x509_set_not_after, 1);\n    rb_define_method(cX509Cert, \"public_key\", ossl_x509_get_public_key, 0);\n    rb_define_method(cX509Cert, \"public_key=\", ossl_x509_set_public_key, 1);\n    rb_define_method(cX509Cert, \"sign\", ossl_x509_sign, 2);\n    rb_define_method(cX509Cert, \"verify\", ossl_x509_verify, 1);\n    rb_define_method(cX509Cert, \"check_private_key\", ossl_x509_check_private_key, 1);\n    rb_define_method(cX509Cert, \"extensions\", ossl_x509_get_extensions, 0);\n    rb_define_method(cX509Cert, \"extensions=\", ossl_x509_set_extensions, 1);\n    rb_define_method(cX509Cert, \"add_extension\", ossl_x509_add_extension, 1);\n    rb_define_method(cX509Cert, \"==\", ossl_x509_eq, 1);\n    rb_define_method(cX509Cert, \"tbs_bytes\", ossl_x509_tbs_bytes, 0);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_x509crl.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewX509CRL(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509crl_type, 0)\n#define SetX509CRL(obj, crl) do { \\\n    if (!(crl)) { \\\n        ossl_raise(rb_eRuntimeError, \"CRL wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (crl); \\\n} while (0)\n#define GetX509CRL(obj, crl) do { \\\n    TypedData_Get_Struct((obj), X509_CRL, &ossl_x509crl_type, (crl)); \\\n    if (!(crl)) { \\\n        ossl_raise(rb_eRuntimeError, \"CRL wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nstatic VALUE cX509CRL;\nstatic VALUE eX509CRLError;\n\nstatic void\nossl_x509crl_free(void *ptr)\n{\n    X509_CRL_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_x509crl_type = {\n    \"OpenSSL/X509/CRL\",\n    {\n        0, ossl_x509crl_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * PUBLIC\n */\nX509_CRL *\nGetX509CRLPtr(VALUE obj)\n{\n    X509_CRL *crl;\n\n    GetX509CRL(obj, crl);\n\n    return crl;\n}\n\nVALUE\nossl_x509crl_new(const X509_CRL *crl)\n{\n    X509_CRL *tmp;\n    VALUE obj;\n\n    obj = NewX509CRL(cX509CRL);\n    /* OpenSSL 1.1.1 takes a non-const pointer */\n    tmp = X509_CRL_dup((X509_CRL *)crl);\n    if (!tmp)\n        ossl_raise(eX509CRLError, \"X509_CRL_dup\");\n    SetX509CRL(obj, tmp);\n\n    return obj;\n}\n\n/*\n * PRIVATE\n */\nstatic VALUE\nossl_x509crl_alloc(VALUE klass)\n{\n    X509_CRL *crl;\n    VALUE obj;\n\n    obj = NewX509CRL(klass);\n    if (!(crl = X509_CRL_new())) {\n        ossl_raise(eX509CRLError, NULL);\n    }\n    SetX509CRL(obj, crl);\n\n    return obj;\n}\n\nstatic VALUE\nossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)\n{\n    BIO *in;\n    X509_CRL *crl, *crl_orig = RTYPEDDATA_DATA(self);\n    VALUE arg;\n\n    rb_check_frozen(self);\n    if (rb_scan_args(argc, argv, \"01\", &arg) == 0) {\n        return self;\n    }\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n    crl = d2i_X509_CRL_bio(in, NULL);\n    if (!crl) {\n        OSSL_BIO_reset(in);\n        crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);\n    }\n    BIO_free(in);\n    if (!crl)\n        ossl_raise(eX509CRLError, \"PEM_read_bio_X509_CRL\");\n\n    RTYPEDDATA_DATA(self) = crl;\n    X509_CRL_free(crl_orig);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_x509crl_copy(VALUE self, VALUE other)\n{\n    X509_CRL *a, *b, *crl;\n\n    rb_check_frozen(self);\n    if (self == other) return self;\n    GetX509CRL(self, a);\n    GetX509CRL(other, b);\n    if (!(crl = X509_CRL_dup(b))) {\n        ossl_raise(eX509CRLError, NULL);\n    }\n    X509_CRL_free(a);\n    DATA_PTR(self) = crl;\n\n    return self;\n}\n\nstatic VALUE\nossl_x509crl_get_version(VALUE self)\n{\n    X509_CRL *crl;\n    long ver;\n\n    GetX509CRL(self, crl);\n    ver = X509_CRL_get_version(crl);\n\n    return LONG2NUM(ver);\n}\n\nstatic VALUE\nossl_x509crl_set_version(VALUE self, VALUE version)\n{\n    X509_CRL *crl;\n    long ver;\n\n    if ((ver = NUM2LONG(version)) < 0) {\n        ossl_raise(eX509CRLError, \"version must be >= 0!\");\n    }\n    GetX509CRL(self, crl);\n    if (!X509_CRL_set_version(crl, ver)) {\n        ossl_raise(eX509CRLError, NULL);\n    }\n\n    return version;\n}\n\n/*\n * call-seq:\n *    crl.signature_algorithm -> string\n *\n * Returns the signature algorithm used to sign this CRL.\n *\n * Returns the long name of the signature algorithm, or the dotted decimal\n * notation if \\OpenSSL does not define a long name for it.\n */\nstatic VALUE\nossl_x509crl_get_signature_algorithm(VALUE self)\n{\n    X509_CRL *crl;\n    const X509_ALGOR *alg;\n    const ASN1_OBJECT *obj;\n\n    GetX509CRL(self, crl);\n    X509_CRL_get0_signature(crl, NULL, &alg);\n    X509_ALGOR_get0(&obj, NULL, NULL, alg);\n    return ossl_asn1obj_to_string_long_name(obj);\n}\n\nstatic VALUE\nossl_x509crl_get_issuer(VALUE self)\n{\n    X509_CRL *crl;\n\n    GetX509CRL(self, crl);\n\n    return ossl_x509name_new(X509_CRL_get_issuer(crl)); /* NO DUP - don't free */\n}\n\nstatic VALUE\nossl_x509crl_set_issuer(VALUE self, VALUE issuer)\n{\n    X509_CRL *crl;\n\n    GetX509CRL(self, crl);\n\n    if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */\n        ossl_raise(eX509CRLError, NULL);\n    }\n    return issuer;\n}\n\nstatic VALUE\nossl_x509crl_get_last_update(VALUE self)\n{\n    X509_CRL *crl;\n    const ASN1_TIME *time;\n\n    GetX509CRL(self, crl);\n    time = X509_CRL_get0_lastUpdate(crl);\n    if (!time)\n        return Qnil;\n\n    return asn1time_to_time(time);\n}\n\nstatic VALUE\nossl_x509crl_set_last_update(VALUE self, VALUE time)\n{\n    X509_CRL *crl;\n    ASN1_TIME *asn1time;\n\n    GetX509CRL(self, crl);\n    asn1time = ossl_x509_time_adjust(NULL, time);\n    if (!X509_CRL_set1_lastUpdate(crl, asn1time)) {\n        ASN1_TIME_free(asn1time);\n        ossl_raise(eX509CRLError, \"X509_CRL_set_lastUpdate\");\n    }\n    ASN1_TIME_free(asn1time);\n\n    return time;\n}\n\nstatic VALUE\nossl_x509crl_get_next_update(VALUE self)\n{\n    X509_CRL *crl;\n    const ASN1_TIME *time;\n\n    GetX509CRL(self, crl);\n    time = X509_CRL_get0_nextUpdate(crl);\n    if (!time)\n        return Qnil;\n\n    return asn1time_to_time(time);\n}\n\nstatic VALUE\nossl_x509crl_set_next_update(VALUE self, VALUE time)\n{\n    X509_CRL *crl;\n    ASN1_TIME *asn1time;\n\n    GetX509CRL(self, crl);\n    asn1time = ossl_x509_time_adjust(NULL, time);\n    if (!X509_CRL_set1_nextUpdate(crl, asn1time)) {\n        ASN1_TIME_free(asn1time);\n        ossl_raise(eX509CRLError, \"X509_CRL_set_nextUpdate\");\n    }\n    ASN1_TIME_free(asn1time);\n\n    return time;\n}\n\nstatic VALUE\nossl_x509crl_get_revoked(VALUE self)\n{\n    X509_CRL *crl;\n    int i, num;\n    STACK_OF(X509_REVOKED) *sk;\n    VALUE ary;\n\n    GetX509CRL(self, crl);\n    sk = X509_CRL_get_REVOKED(crl);\n    if (!sk)\n        return rb_ary_new();\n\n    num = sk_X509_REVOKED_num(sk);\n    ary = rb_ary_new_capa(num);\n    for(i=0; i<num; i++) {\n        const X509_REVOKED *rev = sk_X509_REVOKED_value(sk, i);\n        rb_ary_push(ary, ossl_x509revoked_new(rev));\n    }\n\n    return ary;\n}\n\nstatic VALUE\nossl_x509crl_set_revoked(VALUE self, VALUE ary)\n{\n    X509_CRL *crl;\n    X509_REVOKED *rev;\n    STACK_OF(X509_REVOKED) *sk;\n    long i;\n\n    Check_Type(ary, T_ARRAY);\n    /* All ary members should be X509 Revoked */\n    for (i=0; i<RARRAY_LEN(ary); i++) {\n        OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Rev);\n    }\n    GetX509CRL(self, crl);\n    if ((sk = X509_CRL_get_REVOKED(crl))) {\n        while ((rev = sk_X509_REVOKED_pop(sk)))\n            X509_REVOKED_free(rev);\n    }\n    for (i=0; i<RARRAY_LEN(ary); i++) {\n        rev = DupX509RevokedPtr(RARRAY_AREF(ary, i));\n        if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */\n            X509_REVOKED_free(rev);\n            ossl_raise(eX509CRLError, \"X509_CRL_add0_revoked\");\n        }\n    }\n    X509_CRL_sort(crl);\n\n    return ary;\n}\n\nstatic VALUE\nossl_x509crl_add_revoked(VALUE self, VALUE revoked)\n{\n    X509_CRL *crl;\n    X509_REVOKED *rev;\n\n    GetX509CRL(self, crl);\n    rev = DupX509RevokedPtr(revoked);\n    if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */\n        X509_REVOKED_free(rev);\n        ossl_raise(eX509CRLError, \"X509_CRL_add0_revoked\");\n    }\n    X509_CRL_sort(crl);\n\n    return revoked;\n}\n\nstatic VALUE\nossl_x509crl_sign(VALUE self, VALUE key, VALUE digest)\n{\n    X509_CRL *crl;\n    EVP_PKEY *pkey;\n    const EVP_MD *md;\n    VALUE md_holder;\n\n    GetX509CRL(self, crl);\n    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */\n    /* NULL needed for some key types, e.g. Ed25519 */\n    md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);\n    if (!X509_CRL_sign(crl, pkey, md))\n        ossl_raise(eX509CRLError, \"X509_CRL_sign\");\n\n    return self;\n}\n\nstatic VALUE\nossl_x509crl_verify(VALUE self, VALUE key)\n{\n    X509_CRL *crl;\n    EVP_PKEY *pkey;\n\n    GetX509CRL(self, crl);\n    pkey = GetPKeyPtr(key);\n    ossl_pkey_check_public_key(pkey);\n    switch (X509_CRL_verify(crl, pkey)) {\n      case 1:\n        return Qtrue;\n      case 0:\n        ossl_clear_error();\n        return Qfalse;\n      default:\n        ossl_raise(eX509CRLError, NULL);\n    }\n}\n\nstatic VALUE\nossl_x509crl_to_der(VALUE self)\n{\n    X509_CRL *crl;\n    BIO *out;\n\n    GetX509CRL(self, crl);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eX509CRLError, NULL);\n    }\n    if (!i2d_X509_CRL_bio(out, crl)) {\n        BIO_free(out);\n        ossl_raise(eX509CRLError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\nstatic VALUE\nossl_x509crl_to_pem(VALUE self)\n{\n    X509_CRL *crl;\n    BIO *out;\n\n    GetX509CRL(self, crl);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eX509CRLError, NULL);\n    }\n    if (!PEM_write_bio_X509_CRL(out, crl)) {\n        BIO_free(out);\n        ossl_raise(eX509CRLError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\nstatic VALUE\nossl_x509crl_to_text(VALUE self)\n{\n    X509_CRL *crl;\n    BIO *out;\n\n    GetX509CRL(self, crl);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eX509CRLError, NULL);\n    }\n    if (!X509_CRL_print(out, crl)) {\n        BIO_free(out);\n        ossl_raise(eX509CRLError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\n/*\n * Gets X509v3 extensions as array of X509Ext objects\n */\nstatic VALUE\nossl_x509crl_get_extensions(VALUE self)\n{\n    X509_CRL *crl;\n    int count, i;\n    VALUE ary;\n\n    GetX509CRL(self, crl);\n    count = X509_CRL_get_ext_count(crl);\n    ary = rb_ary_new_capa(count);\n    for (i=0; i<count; i++) {\n        const X509_EXTENSION *ext = X509_CRL_get_ext(crl, i);\n        rb_ary_push(ary, ossl_x509ext_new(ext));\n    }\n\n    return ary;\n}\n\n/*\n * Sets X509_EXTENSIONs\n */\nstatic VALUE\nossl_x509crl_set_extensions(VALUE self, VALUE ary)\n{\n    X509_CRL *crl;\n    X509_EXTENSION *ext;\n    long i;\n\n    Check_Type(ary, T_ARRAY);\n    /* All ary members should be X509 Extensions */\n    for (i=0; i<RARRAY_LEN(ary); i++) {\n        OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);\n    }\n    GetX509CRL(self, crl);\n    for (i = X509_CRL_get_ext_count(crl); i > 0; i--)\n        X509_EXTENSION_free(X509_CRL_delete_ext(crl, 0));\n    for (i=0; i<RARRAY_LEN(ary); i++) {\n        ext = GetX509ExtPtr(RARRAY_AREF(ary, i)); /* NO NEED TO DUP */\n        if (!X509_CRL_add_ext(crl, ext, -1)) {\n            ossl_raise(eX509CRLError, \"X509_CRL_add_ext\");\n        }\n    }\n\n    return ary;\n}\n\nstatic VALUE\nossl_x509crl_add_extension(VALUE self, VALUE extension)\n{\n    X509_CRL *crl;\n    X509_EXTENSION *ext;\n\n    GetX509CRL(self, crl);\n    ext = GetX509ExtPtr(extension);\n    if (!X509_CRL_add_ext(crl, ext, -1)) {\n        ossl_raise(eX509CRLError, NULL);\n    }\n\n    return extension;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_x509crl(void)\n{\n    eX509CRLError = rb_define_class_under(mX509, \"CRLError\", eOSSLError);\n\n    cX509CRL = rb_define_class_under(mX509, \"CRL\", rb_cObject);\n\n    rb_define_alloc_func(cX509CRL, ossl_x509crl_alloc);\n    rb_define_method(cX509CRL, \"initialize\", ossl_x509crl_initialize, -1);\n    rb_define_method(cX509CRL, \"initialize_copy\", ossl_x509crl_copy, 1);\n\n    rb_define_method(cX509CRL, \"version\", ossl_x509crl_get_version, 0);\n    rb_define_method(cX509CRL, \"version=\", ossl_x509crl_set_version, 1);\n    rb_define_method(cX509CRL, \"signature_algorithm\", ossl_x509crl_get_signature_algorithm, 0);\n    rb_define_method(cX509CRL, \"issuer\", ossl_x509crl_get_issuer, 0);\n    rb_define_method(cX509CRL, \"issuer=\", ossl_x509crl_set_issuer, 1);\n    rb_define_method(cX509CRL, \"last_update\", ossl_x509crl_get_last_update, 0);\n    rb_define_method(cX509CRL, \"last_update=\", ossl_x509crl_set_last_update, 1);\n    rb_define_method(cX509CRL, \"next_update\", ossl_x509crl_get_next_update, 0);\n    rb_define_method(cX509CRL, \"next_update=\", ossl_x509crl_set_next_update, 1);\n    rb_define_method(cX509CRL, \"revoked\", ossl_x509crl_get_revoked, 0);\n    rb_define_method(cX509CRL, \"revoked=\", ossl_x509crl_set_revoked, 1);\n    rb_define_method(cX509CRL, \"add_revoked\", ossl_x509crl_add_revoked, 1);\n    rb_define_method(cX509CRL, \"sign\", ossl_x509crl_sign, 2);\n    rb_define_method(cX509CRL, \"verify\", ossl_x509crl_verify, 1);\n    rb_define_method(cX509CRL, \"to_der\", ossl_x509crl_to_der, 0);\n    rb_define_method(cX509CRL, \"to_pem\", ossl_x509crl_to_pem, 0);\n    rb_define_alias(cX509CRL, \"to_s\", \"to_pem\");\n    rb_define_method(cX509CRL, \"to_text\", ossl_x509crl_to_text, 0);\n    rb_define_method(cX509CRL, \"extensions\", ossl_x509crl_get_extensions, 0);\n    rb_define_method(cX509CRL, \"extensions=\", ossl_x509crl_set_extensions, 1);\n    rb_define_method(cX509CRL, \"add_extension\", ossl_x509crl_add_extension, 1);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_x509ext.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewX509Ext(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509ext_type, 0)\n#define SetX509Ext(obj, ext) do { \\\n    if (!(ext)) { \\\n        ossl_raise(rb_eRuntimeError, \"EXT wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (ext); \\\n} while (0)\n#define GetX509Ext(obj, ext) do { \\\n    TypedData_Get_Struct((obj), X509_EXTENSION, &ossl_x509ext_type, (ext)); \\\n    if (!(ext)) { \\\n        ossl_raise(rb_eRuntimeError, \"EXT wasn't initialized!\"); \\\n    } \\\n} while (0)\n#define MakeX509ExtFactory(klass, obj, ctx) do { \\\n    (obj) = TypedData_Wrap_Struct((klass), &ossl_x509extfactory_type, 0); \\\n    if (!((ctx) = OPENSSL_malloc(sizeof(X509V3_CTX)))) \\\n        ossl_raise(rb_eRuntimeError, \"CTX wasn't allocated!\"); \\\n    X509V3_set_ctx((ctx), NULL, NULL, NULL, NULL, 0); \\\n    RTYPEDDATA_DATA(obj) = (ctx); \\\n} while (0)\n#define GetX509ExtFactory(obj, ctx) do { \\\n    TypedData_Get_Struct((obj), X509V3_CTX, &ossl_x509extfactory_type, (ctx)); \\\n    if (!(ctx)) { \\\n        ossl_raise(rb_eRuntimeError, \"CTX wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nVALUE cX509Ext;\nstatic VALUE cX509ExtFactory;\nstatic VALUE eX509ExtError;\n\nstatic void\nossl_x509ext_free(void *ptr)\n{\n    X509_EXTENSION_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_x509ext_type = {\n    \"OpenSSL/X509/EXTENSION\",\n    {\n        0, ossl_x509ext_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Public\n */\nVALUE\nossl_x509ext_new(const X509_EXTENSION *ext)\n{\n    X509_EXTENSION *new;\n    VALUE obj;\n\n    obj = NewX509Ext(cX509Ext);\n    /* OpenSSL 1.1.1 takes a non-const pointer */\n    new = X509_EXTENSION_dup((X509_EXTENSION *)ext);\n    if (!new)\n        ossl_raise(eX509ExtError, \"X509_EXTENSION_dup\");\n    SetX509Ext(obj, new);\n\n    return obj;\n}\n\nX509_EXTENSION *\nGetX509ExtPtr(VALUE obj)\n{\n    X509_EXTENSION *ext;\n\n    GetX509Ext(obj, ext);\n\n    return ext;\n}\n\n/*\n * Private\n */\n/*\n * Ext factory\n */\nstatic void\nossl_x509extfactory_free(void *ctx)\n{\n    OPENSSL_free(ctx);\n}\n\nstatic const rb_data_type_t ossl_x509extfactory_type = {\n    \"OpenSSL/X509/EXTENSION/Factory\",\n    {\n        0, ossl_x509extfactory_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_x509extfactory_alloc(VALUE klass)\n{\n    X509V3_CTX *ctx;\n    VALUE obj;\n\n    MakeX509ExtFactory(klass, obj, ctx);\n    rb_iv_set(obj, \"@config\", Qnil);\n\n    return obj;\n}\n\nstatic VALUE\nossl_x509extfactory_set_issuer_cert(VALUE self, VALUE cert)\n{\n    X509V3_CTX *ctx;\n\n    GetX509ExtFactory(self, ctx);\n    rb_iv_set(self, \"@issuer_certificate\", cert);\n    ctx->issuer_cert = GetX509CertPtr(cert); /* NO DUP NEEDED */\n\n    return cert;\n}\n\nstatic VALUE\nossl_x509extfactory_set_subject_cert(VALUE self, VALUE cert)\n{\n    X509V3_CTX *ctx;\n\n    GetX509ExtFactory(self, ctx);\n    rb_iv_set(self, \"@subject_certificate\", cert);\n    ctx->subject_cert = GetX509CertPtr(cert); /* NO DUP NEEDED */\n\n    return cert;\n}\n\nstatic VALUE\nossl_x509extfactory_set_subject_req(VALUE self, VALUE req)\n{\n    X509V3_CTX *ctx;\n\n    GetX509ExtFactory(self, ctx);\n    rb_iv_set(self, \"@subject_request\", req);\n    ctx->subject_req = GetX509ReqPtr(req); /* NO DUP NEEDED */\n\n    return req;\n}\n\nstatic VALUE\nossl_x509extfactory_set_crl(VALUE self, VALUE crl)\n{\n    X509V3_CTX *ctx;\n\n    GetX509ExtFactory(self, ctx);\n    rb_iv_set(self, \"@crl\", crl);\n    ctx->crl = GetX509CRLPtr(crl); /* NO DUP NEEDED */\n\n    return crl;\n}\n\nstatic VALUE\nossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)\n{\n    /*X509V3_CTX *ctx;*/\n    VALUE issuer_cert, subject_cert, subject_req, crl;\n\n    /*GetX509ExtFactory(self, ctx);*/\n\n    rb_scan_args(argc, argv, \"04\",\n                 &issuer_cert, &subject_cert, &subject_req, &crl);\n    if (!NIL_P(issuer_cert))\n        ossl_x509extfactory_set_issuer_cert(self, issuer_cert);\n    if (!NIL_P(subject_cert))\n        ossl_x509extfactory_set_subject_cert(self, subject_cert);\n    if (!NIL_P(subject_req))\n        ossl_x509extfactory_set_subject_req(self, subject_req);\n    if (!NIL_P(crl))\n        ossl_x509extfactory_set_crl(self, crl);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   ef.create_ext(ln_or_sn, \"value\", critical = false) -> X509::Extension\n *   ef.create_ext(ln_or_sn, \"critical,value\")          -> X509::Extension\n *\n * Creates a new X509::Extension with passed values. See also x509v3_config(5).\n */\nstatic VALUE\nossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)\n{\n    X509V3_CTX *ctx;\n    X509_EXTENSION *ext;\n    VALUE oid, value, critical, valstr, obj;\n    int nid;\n    VALUE rconf;\n    CONF *conf;\n    const char *oid_cstr = NULL;\n\n    rb_scan_args(argc, argv, \"21\", &oid, &value, &critical);\n    StringValue(value);\n    if(NIL_P(critical)) critical = Qfalse;\n\n    oid_cstr = StringValueCStr(oid);\n    nid = OBJ_ln2nid(oid_cstr);\n    if (nid != NID_undef)\n        oid_cstr = OBJ_nid2sn(nid);\n\n    valstr = rb_str_new2(RTEST(critical) ? \"critical,\" : \"\");\n    rb_str_append(valstr, value);\n    StringValueCStr(valstr);\n\n    GetX509ExtFactory(self, ctx);\n    obj = NewX509Ext(cX509Ext);\n    rconf = rb_iv_get(self, \"@config\");\n    conf = NIL_P(rconf) ? NULL : GetConfig(rconf);\n    X509V3_set_nconf(ctx, conf);\n\n    ext = X509V3_EXT_nconf(conf, ctx, oid_cstr, RSTRING_PTR(valstr));\n    X509V3_set_ctx_nodb(ctx);\n    if (!ext){\n        ossl_raise(eX509ExtError, \"%\"PRIsVALUE\" = %\"PRIsVALUE, oid, valstr);\n    }\n    SetX509Ext(obj, ext);\n\n    return obj;\n}\n\n/*\n * Ext\n */\nstatic VALUE\nossl_x509ext_alloc(VALUE klass)\n{\n    X509_EXTENSION *ext;\n    VALUE obj;\n\n    obj = NewX509Ext(klass);\n    if(!(ext = X509_EXTENSION_new())){\n        ossl_raise(eX509ExtError, NULL);\n    }\n    SetX509Ext(obj, ext);\n\n    return obj;\n}\n\n/*\n * call-seq:\n *    OpenSSL::X509::Extension.new(der)\n *    OpenSSL::X509::Extension.new(oid, value)\n *    OpenSSL::X509::Extension.new(oid, value, critical)\n *\n * Creates an X509 extension.\n *\n * The extension may be created from _der_ data or from an extension _oid_\n * and _value_.  The _oid_ may be either an OID or an extension name.  If\n * _critical_ is +true+ the extension is marked critical.\n */\nstatic VALUE\nossl_x509ext_initialize(int argc, VALUE *argv, VALUE self)\n{\n    VALUE oid, value, critical;\n    const unsigned char *p;\n    X509_EXTENSION *ext, *x;\n\n    GetX509Ext(self, ext);\n    if(rb_scan_args(argc, argv, \"12\", &oid, &value, &critical) == 1){\n        oid = ossl_to_der_if_possible(oid);\n        StringValue(oid);\n        p = (unsigned char *)RSTRING_PTR(oid);\n        x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));\n        DATA_PTR(self) = ext;\n        if(!x)\n            ossl_raise(eX509ExtError, NULL);\n        return self;\n    }\n    rb_funcall(self, rb_intern(\"oid=\"), 1, oid);\n    rb_funcall(self, rb_intern(\"value=\"), 1, value);\n    if(argc > 2) rb_funcall(self, rb_intern(\"critical=\"), 1, critical);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_x509ext_initialize_copy(VALUE self, VALUE other)\n{\n    X509_EXTENSION *ext, *ext_other, *ext_new;\n\n    rb_check_frozen(self);\n    GetX509Ext(self, ext);\n    GetX509Ext(other, ext_other);\n\n    ext_new = X509_EXTENSION_dup(ext_other);\n    if (!ext_new)\n        ossl_raise(eX509ExtError, \"X509_EXTENSION_dup\");\n\n    SetX509Ext(self, ext_new);\n    X509_EXTENSION_free(ext);\n\n    return self;\n}\n\nstatic VALUE\nossl_x509ext_set_oid(VALUE self, VALUE oid)\n{\n    X509_EXTENSION *ext;\n    ASN1_OBJECT *obj;\n\n    GetX509Ext(self, ext);\n    obj = OBJ_txt2obj(StringValueCStr(oid), 0);\n    if (!obj)\n        ossl_raise(eX509ExtError, \"OBJ_txt2obj\");\n    if (!X509_EXTENSION_set_object(ext, obj)) {\n        ASN1_OBJECT_free(obj);\n        ossl_raise(eX509ExtError, \"X509_EXTENSION_set_object\");\n    }\n    ASN1_OBJECT_free(obj);\n\n    return oid;\n}\n\nstatic VALUE\nossl_x509ext_set_value(VALUE self, VALUE data)\n{\n    X509_EXTENSION *ext;\n    ASN1_OCTET_STRING *asn1s;\n\n    GetX509Ext(self, ext);\n    data = ossl_to_der_if_possible(data);\n    StringValue(data);\n\n    asn1s = ASN1_OCTET_STRING_new();\n    if (!asn1s)\n        ossl_raise(eX509ExtError, \"ASN1_OCTET_STRING_new\");\n    if (!ASN1_OCTET_STRING_set(asn1s, (unsigned char *)RSTRING_PTR(data),\n                               RSTRING_LENINT(data))) {\n        ASN1_OCTET_STRING_free(asn1s);\n        ossl_raise(eX509ExtError, \"ASN1_OCTET_STRING_set\");\n    }\n    if (!X509_EXTENSION_set_data(ext, asn1s)) {\n        ASN1_OCTET_STRING_free(asn1s);\n        ossl_raise(eX509ExtError, \"X509_EXTENSION_set_data\");\n    }\n    ASN1_OCTET_STRING_free(asn1s);\n\n    return data;\n}\n\nstatic VALUE\nossl_x509ext_set_critical(VALUE self, VALUE flag)\n{\n    X509_EXTENSION *ext;\n\n    GetX509Ext(self, ext);\n    X509_EXTENSION_set_critical(ext, RTEST(flag) ? 1 : 0);\n\n    return flag;\n}\n\n/*\n * call-seq:\n *    ext.oid -> string\n *\n * Returns the OID of the extension. Returns the short name or the dotted\n * decimal notation.\n */\nstatic VALUE\nossl_x509ext_get_oid(VALUE obj)\n{\n    X509_EXTENSION *ext;\n\n    GetX509Ext(obj, ext);\n    return ossl_asn1obj_to_string(X509_EXTENSION_get_object(ext));\n}\n\nstatic VALUE\nossl_x509ext_get_value(VALUE obj)\n{\n    X509_EXTENSION *ext;\n    BIO *out;\n    VALUE ret;\n\n    GetX509Ext(obj, ext);\n    if (!(out = BIO_new(BIO_s_mem())))\n        ossl_raise(eX509ExtError, NULL);\n    if (!X509V3_EXT_print(out, ext, 0, 0))\n        ASN1_STRING_print(out, X509_EXTENSION_get_data(ext));\n    ret = ossl_membio2str(out);\n\n    return ret;\n}\n\nstatic VALUE\nossl_x509ext_get_value_der(VALUE obj)\n{\n    X509_EXTENSION *ext;\n    const ASN1_OCTET_STRING *value;\n\n    GetX509Ext(obj, ext);\n    if ((value = X509_EXTENSION_get_data(ext)) == NULL)\n        ossl_raise(eX509ExtError, NULL);\n\n    return asn1str_to_str(value);\n}\n\nstatic VALUE\nossl_x509ext_get_critical(VALUE obj)\n{\n    X509_EXTENSION *ext;\n\n    GetX509Ext(obj, ext);\n    return X509_EXTENSION_get_critical(ext) ? Qtrue : Qfalse;\n}\n\nstatic VALUE\nossl_x509ext_to_der(VALUE obj)\n{\n    X509_EXTENSION *ext;\n    unsigned char *p;\n    long len;\n    VALUE str;\n\n    GetX509Ext(obj, ext);\n    if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)\n        ossl_raise(eX509ExtError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d_X509_EXTENSION(ext, &p) < 0)\n        ossl_raise(eX509ExtError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_x509ext(void)\n{\n#undef rb_intern\n    eX509ExtError = rb_define_class_under(mX509, \"ExtensionError\", eOSSLError);\n\n    cX509ExtFactory = rb_define_class_under(mX509, \"ExtensionFactory\", rb_cObject);\n\n    rb_define_alloc_func(cX509ExtFactory, ossl_x509extfactory_alloc);\n    rb_define_method(cX509ExtFactory, \"initialize\", ossl_x509extfactory_initialize, -1);\n\n    rb_attr(cX509ExtFactory, rb_intern(\"issuer_certificate\"), 1, 0, Qfalse);\n    rb_attr(cX509ExtFactory, rb_intern(\"subject_certificate\"), 1, 0, Qfalse);\n    rb_attr(cX509ExtFactory, rb_intern(\"subject_request\"), 1, 0, Qfalse);\n    rb_attr(cX509ExtFactory, rb_intern(\"crl\"), 1, 0, Qfalse);\n    rb_attr(cX509ExtFactory, rb_intern(\"config\"), 1, 1, Qfalse);\n\n    rb_define_method(cX509ExtFactory, \"issuer_certificate=\", ossl_x509extfactory_set_issuer_cert, 1);\n    rb_define_method(cX509ExtFactory, \"subject_certificate=\", ossl_x509extfactory_set_subject_cert, 1);\n    rb_define_method(cX509ExtFactory, \"subject_request=\", ossl_x509extfactory_set_subject_req, 1);\n    rb_define_method(cX509ExtFactory, \"crl=\", ossl_x509extfactory_set_crl, 1);\n    rb_define_method(cX509ExtFactory, \"create_ext\", ossl_x509extfactory_create_ext, -1);\n\n    cX509Ext = rb_define_class_under(mX509, \"Extension\", rb_cObject);\n    rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc);\n    rb_define_method(cX509Ext, \"initialize\", ossl_x509ext_initialize, -1);\n    rb_define_method(cX509Ext, \"initialize_copy\", ossl_x509ext_initialize_copy, 1);\n    rb_define_method(cX509Ext, \"oid=\", ossl_x509ext_set_oid, 1);\n    rb_define_method(cX509Ext, \"value=\", ossl_x509ext_set_value, 1);\n    rb_define_method(cX509Ext, \"critical=\", ossl_x509ext_set_critical, 1);\n    rb_define_method(cX509Ext, \"oid\", ossl_x509ext_get_oid, 0);\n    rb_define_method(cX509Ext, \"value\", ossl_x509ext_get_value, 0);\n    rb_define_method(cX509Ext, \"value_der\", ossl_x509ext_get_value_der, 0);\n    rb_define_method(cX509Ext, \"critical?\", ossl_x509ext_get_critical, 0);\n    rb_define_method(cX509Ext, \"to_der\", ossl_x509ext_to_der, 0);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_x509name.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewX509Name(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509name_type, 0)\n#define SetX509Name(obj, name) do { \\\n    if (!(name)) { \\\n        ossl_raise(rb_eRuntimeError, \"Name wasn't initialized.\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (name); \\\n} while (0)\n#define GetX509Name(obj, name) do { \\\n    TypedData_Get_Struct((obj), X509_NAME, &ossl_x509name_type, (name)); \\\n    if (!(name)) { \\\n        ossl_raise(rb_eRuntimeError, \"Name wasn't initialized.\"); \\\n    } \\\n} while (0)\n\n#define OBJECT_TYPE_TEMPLATE \\\n    rb_const_get(cX509Name, rb_intern(\"OBJECT_TYPE_TEMPLATE\"))\n#define DEFAULT_OBJECT_TYPE \\\n    rb_const_get(cX509Name, rb_intern(\"DEFAULT_OBJECT_TYPE\"))\n\n/*\n * Classes\n */\nstatic VALUE cX509Name;\nstatic VALUE eX509NameError;\n\nstatic void\nossl_x509name_free(void *ptr)\n{\n    X509_NAME_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_x509name_type = {\n    \"OpenSSL/X509/NAME\",\n    {\n        0, ossl_x509name_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Public\n */\nVALUE\nossl_x509name_new(const X509_NAME *name)\n{\n    X509_NAME *new;\n    VALUE obj;\n\n    obj = NewX509Name(cX509Name);\n    /* OpenSSL 1.1.1 takes a non-const pointer */\n    new = X509_NAME_dup((X509_NAME *)name);\n    if (!new)\n        ossl_raise(eX509NameError, \"X509_NAME_dup\");\n    SetX509Name(obj, new);\n\n    return obj;\n}\n\nX509_NAME *\nGetX509NamePtr(VALUE obj)\n{\n    X509_NAME *name;\n\n    GetX509Name(obj, name);\n\n    return name;\n}\n\n/*\n * Private\n */\nstatic VALUE\nossl_x509name_alloc(VALUE klass)\n{\n    X509_NAME *name;\n    VALUE obj;\n\n    obj = NewX509Name(klass);\n    if (!(name = X509_NAME_new())) {\n        ossl_raise(eX509NameError, NULL);\n    }\n    SetX509Name(obj, name);\n\n    return obj;\n}\n\nstatic ID id_aref;\nstatic VALUE ossl_x509name_add_entry(int, VALUE*, VALUE);\n#define rb_aref(obj, key) rb_funcall((obj), id_aref, 1, (key))\n\nstatic VALUE\nossl_x509name_init_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))\n{\n    VALUE self = rb_ary_entry(args, 0);\n    VALUE template = rb_ary_entry(args, 1);\n    VALUE entry[3];\n\n    Check_Type(i, T_ARRAY);\n    entry[0] = rb_ary_entry(i, 0);\n    entry[1] = rb_ary_entry(i, 1);\n    entry[2] = rb_ary_entry(i, 2);\n    if(NIL_P(entry[2])) entry[2] = rb_aref(template, entry[0]);\n    if(NIL_P(entry[2])) entry[2] = DEFAULT_OBJECT_TYPE;\n    ossl_x509name_add_entry(3, entry, self);\n\n    return Qnil;\n}\n\n/*\n * call-seq:\n *    X509::Name.new                               => name\n *    X509::Name.new(der)                          => name\n *    X509::Name.new(distinguished_name)           => name\n *    X509::Name.new(distinguished_name, template) => name\n *\n * Creates a new Name.\n *\n * A name may be created from a DER encoded string _der_, an Array\n * representing a _distinguished_name_ or a _distinguished_name_ along with a\n * _template_.\n *\n *   name = OpenSSL::X509::Name.new [['CN', 'nobody'], ['DC', 'example']]\n *\n *   name = OpenSSL::X509::Name.new name.to_der\n *\n * See add_entry for a description of the _distinguished_name_ Array's\n * contents\n */\nstatic VALUE\nossl_x509name_initialize(int argc, VALUE *argv, VALUE self)\n{\n    X509_NAME *name;\n    VALUE arg, template;\n\n    GetX509Name(self, name);\n    if (rb_scan_args(argc, argv, \"02\", &arg, &template) == 0) {\n        return self;\n    }\n    else {\n        VALUE tmp = rb_check_array_type(arg);\n        if (!NIL_P(tmp)) {\n            VALUE args;\n            if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;\n            args = rb_ary_new3(2, self, template);\n            rb_block_call(tmp, rb_intern(\"each\"), 0, 0, ossl_x509name_init_i, args);\n        }\n        else{\n            const unsigned char *p;\n            VALUE str = ossl_to_der_if_possible(arg);\n            X509_NAME *x;\n            StringValue(str);\n            p = (unsigned char *)RSTRING_PTR(str);\n            x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));\n            DATA_PTR(self) = name;\n            if(!x){\n                ossl_raise(eX509NameError, NULL);\n            }\n        }\n    }\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_x509name_initialize_copy(VALUE self, VALUE other)\n{\n    X509_NAME *name, *name_other, *name_new;\n\n    rb_check_frozen(self);\n    GetX509Name(self, name);\n    GetX509Name(other, name_other);\n\n    name_new = X509_NAME_dup(name_other);\n    if (!name_new)\n        ossl_raise(eX509NameError, \"X509_NAME_dup\");\n\n    SetX509Name(self, name_new);\n    X509_NAME_free(name);\n\n    return self;\n}\n\n/*\n * call-seq:\n *    name.add_entry(oid, value [, type], loc: -1, set: 0) => self\n *\n * Adds a new entry with the given _oid_ and _value_ to this name.  The _oid_\n * is an object identifier defined in ASN.1.  Some common OIDs are:\n *\n * C::  Country Name\n * CN:: Common Name\n * DC:: Domain Component\n * O::  Organization Name\n * OU:: Organizational Unit Name\n * ST:: State or Province Name\n *\n * The optional keyword parameters _loc_ and _set_ specify where to insert the\n * new attribute. Refer to the manpage of X509_NAME_add_entry(3) for details.\n * _loc_ defaults to -1 and _set_ defaults to 0. This appends a single-valued\n * RDN to the end.\n */\nstatic\nVALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)\n{\n    X509_NAME *name;\n    VALUE oid, value, type, opts, kwargs[2];\n    static ID kwargs_ids[2];\n    const char *oid_name;\n    int loc = -1, set = 0;\n\n    if (!kwargs_ids[0]) {\n        kwargs_ids[0] = rb_intern_const(\"loc\");\n        kwargs_ids[1] = rb_intern_const(\"set\");\n    }\n    rb_scan_args(argc, argv, \"21:\", &oid, &value, &type, &opts);\n    rb_get_kwargs(opts, kwargs_ids, 0, 2, kwargs);\n    oid_name = StringValueCStr(oid);\n    StringValue(value);\n    if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid);\n    if (kwargs[0] != Qundef)\n        loc = NUM2INT(kwargs[0]);\n    if (kwargs[1] != Qundef)\n        set = NUM2INT(kwargs[1]);\n    GetX509Name(self, name);\n    if (!X509_NAME_add_entry_by_txt(name, oid_name, NUM2INT(type),\n                                    (unsigned char *)RSTRING_PTR(value),\n                                    RSTRING_LENINT(value), loc, set))\n        ossl_raise(eX509NameError, \"X509_NAME_add_entry_by_txt\");\n    return self;\n}\n\nstatic VALUE\nossl_x509name_to_s_old(VALUE self)\n{\n    X509_NAME *name;\n    char *buf;\n\n    GetX509Name(self, name);\n    buf = X509_NAME_oneline(name, NULL, 0);\n    if (!buf)\n        ossl_raise(eX509NameError, \"X509_NAME_oneline\");\n    return ossl_buf2str(buf, rb_long2int(strlen(buf)));\n}\n\nstatic VALUE\nx509name_print(VALUE self, unsigned long iflag)\n{\n    X509_NAME *name;\n    BIO *out;\n    int ret;\n\n    GetX509Name(self, name);\n    out = BIO_new(BIO_s_mem());\n    if (!out)\n        ossl_raise(eX509NameError, NULL);\n    ret = X509_NAME_print_ex(out, name, 0, iflag);\n    if (ret < 0 || (iflag == XN_FLAG_COMPAT && ret == 0)) {\n        BIO_free(out);\n        ossl_raise(eX509NameError, \"X509_NAME_print_ex\");\n    }\n    return ossl_membio2str(out);\n}\n\n/*\n * call-seq:\n *    name.to_s         -> string\n *    name.to_s(format) -> string\n *\n * Returns a String representation of the Distinguished Name. _format_ is\n * one of:\n *\n * * OpenSSL::X509::Name::COMPAT\n * * OpenSSL::X509::Name::RFC2253\n * * OpenSSL::X509::Name::ONELINE\n * * OpenSSL::X509::Name::MULTILINE\n *\n * If _format_ is omitted, the largely broken and traditional OpenSSL format\n * (<tt>X509_NAME_oneline()</tt> format) is chosen.\n *\n * <b>Use of this method is discouraged.</b> None of the formats other than\n * OpenSSL::X509::Name::RFC2253 is standardized and may show an inconsistent\n * behavior through \\OpenSSL versions.\n *\n * It is recommended to use #to_utf8 instead, which is equivalent to calling\n * <tt>name.to_s(OpenSSL::X509::Name::RFC2253).force_encoding(\"UTF-8\")</tt>.\n */\nstatic VALUE\nossl_x509name_to_s(int argc, VALUE *argv, VALUE self)\n{\n    rb_check_arity(argc, 0, 1);\n    /* name.to_s(nil) was allowed */\n    if (!argc || NIL_P(argv[0]))\n        return ossl_x509name_to_s_old(self);\n    else\n        return x509name_print(self, NUM2ULONG(argv[0]));\n}\n\n/*\n * call-seq:\n *    name.to_utf8 -> string\n *\n * Returns an UTF-8 representation of the distinguished name, as specified\n * in {RFC 2253}[https://www.ietf.org/rfc/rfc2253.txt].\n */\nstatic VALUE\nossl_x509name_to_utf8(VALUE self)\n{\n    VALUE str = x509name_print(self, XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB);\n    rb_enc_associate_index(str, rb_utf8_encindex());\n    return str;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_x509name_inspect(VALUE self)\n{\n    return rb_enc_sprintf(rb_utf8_encoding(), \"#<%\"PRIsVALUE\" %\"PRIsVALUE\">\",\n                          rb_obj_class(self), ossl_x509name_to_utf8(self));\n}\n\n/*\n * call-seq:\n *    name.to_a => [[name, data, type], ...]\n *\n * Returns an Array representation of the distinguished name suitable for\n * passing to ::new\n */\nstatic VALUE\nossl_x509name_to_a(VALUE self)\n{\n    X509_NAME *name;\n    int entries;\n    VALUE ret;\n\n    GetX509Name(self, name);\n    entries = X509_NAME_entry_count(name);\n    ret = rb_ary_new_capa(entries);\n    for (int i = 0; i < entries; i++) {\n        const X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, i);\n        if (!entry)\n            ossl_raise(eX509NameError, \"X509_NAME_get_entry\");\n        const ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(entry);\n        VALUE vname = ossl_asn1obj_to_string(obj);\n        const ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry);\n        VALUE vdata = asn1str_to_str(data);\n        VALUE type = INT2NUM(ASN1_STRING_type(data));\n        rb_ary_push(ret, rb_ary_new_from_args(3, vname, vdata, type));\n    }\n    return ret;\n}\n\nstatic int\nossl_x509name_cmp0(VALUE self, VALUE other)\n{\n    X509_NAME *name1, *name2;\n    int result;\n\n    GetX509Name(self, name1);\n    GetX509Name(other, name2);\n\n    result = X509_NAME_cmp(name1, name2);\n    if (result == -2) {\n        ossl_raise(eX509NameError, NULL);\n    }\n\n    return result;\n}\n\n/*\n * call-seq:\n *    name.cmp(other) -> -1 | 0 | 1 | nil\n *    name <=> other  -> -1 | 0 | 1 | nil\n *\n * Compares this Name with _other_ and returns +0+ if they are the same and +-1+\n * or ++1+ if they are greater or less than each other respectively.\n * Returns +nil+ if they are not comparable (i.e. different types).\n */\nstatic VALUE\nossl_x509name_cmp(VALUE self, VALUE other)\n{\n    int result;\n\n    if (!rb_obj_is_kind_of(other, cX509Name))\n        return Qnil;\n\n    result = ossl_x509name_cmp0(self, other);\n    if (result < 0) return INT2FIX(-1);\n    if (result > 0) return INT2FIX(1);\n\n    return INT2FIX(0);\n}\n\n/*\n * call-seq:\n *   name.eql?(other) -> true | false\n *\n * Returns true if _name_ and _other_ refer to the same hash key.\n */\nstatic VALUE\nossl_x509name_eql(VALUE self, VALUE other)\n{\n    if (!rb_obj_is_kind_of(other, cX509Name))\n        return Qfalse;\n\n    return ossl_x509name_cmp0(self, other) == 0 ? Qtrue : Qfalse;\n}\n\n/*\n * call-seq:\n *    name.hash => integer\n *\n * The hash value returned is suitable for use as a certificate's filename in\n * a CA path.\n */\nstatic VALUE\nossl_x509name_hash(VALUE self)\n{\n    X509_NAME *name;\n    unsigned long hash;\n\n    GetX509Name(self, name);\n\n    hash = X509_NAME_hash(name);\n\n    return ULONG2NUM(hash);\n}\n\n/*\n * call-seq:\n *    name.hash_old => integer\n *\n * Returns an MD5 based hash used in OpenSSL 0.9.X.\n */\nstatic VALUE\nossl_x509name_hash_old(VALUE self)\n{\n    X509_NAME *name;\n    unsigned long hash;\n\n    GetX509Name(self, name);\n\n    hash = X509_NAME_hash_old(name);\n\n    return ULONG2NUM(hash);\n}\n\n/*\n * call-seq:\n *    name.to_der => string\n *\n * Converts the name to DER encoding\n */\nstatic VALUE\nossl_x509name_to_der(VALUE self)\n{\n    X509_NAME *name;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetX509Name(self, name);\n    if((len = i2d_X509_NAME(name, NULL)) <= 0)\n        ossl_raise(eX509NameError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if(i2d_X509_NAME(name, &p) <= 0)\n        ossl_raise(eX509NameError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\n/*\n * Document-class: OpenSSL::X509::Name\n *\n * An X.509 name represents a hostname, email address or other entity\n * associated with a public key.\n *\n * You can create a Name by parsing a distinguished name String or by\n * supplying the distinguished name as an Array.\n *\n *   name = OpenSSL::X509::Name.parse_rfc2253 'DC=example,CN=nobody'\n *\n *   name = OpenSSL::X509::Name.new [['CN', 'nobody'], ['DC', 'example']]\n */\n\nvoid\nInit_ossl_x509name(void)\n{\n#undef rb_intern\n    VALUE utf8str, ptrstr, ia5str, hash;\n\n    id_aref = rb_intern(\"[]\");\n    eX509NameError = rb_define_class_under(mX509, \"NameError\", eOSSLError);\n    cX509Name = rb_define_class_under(mX509, \"Name\", rb_cObject);\n\n    rb_include_module(cX509Name, rb_mComparable);\n\n    rb_define_alloc_func(cX509Name, ossl_x509name_alloc);\n    rb_define_method(cX509Name, \"initialize\", ossl_x509name_initialize, -1);\n    rb_define_method(cX509Name, \"initialize_copy\", ossl_x509name_initialize_copy, 1);\n    rb_define_method(cX509Name, \"add_entry\", ossl_x509name_add_entry, -1);\n    rb_define_method(cX509Name, \"to_s\", ossl_x509name_to_s, -1);\n    rb_define_method(cX509Name, \"to_utf8\", ossl_x509name_to_utf8, 0);\n    rb_define_method(cX509Name, \"inspect\", ossl_x509name_inspect, 0);\n    rb_define_method(cX509Name, \"to_a\", ossl_x509name_to_a, 0);\n    rb_define_method(cX509Name, \"cmp\", ossl_x509name_cmp, 1);\n    rb_define_alias(cX509Name, \"<=>\", \"cmp\");\n    rb_define_method(cX509Name, \"eql?\", ossl_x509name_eql, 1);\n    rb_define_method(cX509Name, \"hash\", ossl_x509name_hash, 0);\n    rb_define_method(cX509Name, \"hash_old\", ossl_x509name_hash_old, 0);\n    rb_define_method(cX509Name, \"to_der\", ossl_x509name_to_der, 0);\n\n    utf8str = INT2NUM(V_ASN1_UTF8STRING);\n    ptrstr = INT2NUM(V_ASN1_PRINTABLESTRING);\n    ia5str = INT2NUM(V_ASN1_IA5STRING);\n\n    /*\n     * The default object type for name entries.\n     */\n    rb_define_const(cX509Name, \"DEFAULT_OBJECT_TYPE\", utf8str);\n    hash = rb_hash_new();\n    RHASH_SET_IFNONE(hash, utf8str);\n    rb_hash_aset(hash, rb_str_new2(\"C\"), ptrstr);\n    rb_hash_aset(hash, rb_str_new2(\"countryName\"), ptrstr);\n    rb_hash_aset(hash, rb_str_new2(\"serialNumber\"), ptrstr);\n    rb_hash_aset(hash, rb_str_new2(\"dnQualifier\"), ptrstr);\n    rb_hash_aset(hash, rb_str_new2(\"DC\"), ia5str);\n    rb_hash_aset(hash, rb_str_new2(\"domainComponent\"), ia5str);\n    rb_hash_aset(hash, rb_str_new2(\"emailAddress\"), ia5str);\n    rb_obj_freeze(hash);\n\n    /*\n     * The default object type template for name entries.\n     */\n    rb_define_const(cX509Name, \"OBJECT_TYPE_TEMPLATE\", hash);\n\n    /*\n     * A flag for #to_s.\n     *\n     * Breaks the name returned into multiple lines if longer than 80\n     * characters.\n     */\n    rb_define_const(cX509Name, \"COMPAT\", ULONG2NUM(XN_FLAG_COMPAT));\n\n    /*\n     * A flag for #to_s.\n     *\n     * Returns an RFC2253 format name.\n     */\n    rb_define_const(cX509Name, \"RFC2253\", ULONG2NUM(XN_FLAG_RFC2253));\n\n    /*\n     * A flag for #to_s.\n     *\n     * Returns a more readable format than RFC2253.\n     */\n    rb_define_const(cX509Name, \"ONELINE\", ULONG2NUM(XN_FLAG_ONELINE));\n\n    /*\n     * A flag for #to_s.\n     *\n     * Returns a multiline format.\n     */\n    rb_define_const(cX509Name, \"MULTILINE\", ULONG2NUM(XN_FLAG_MULTILINE));\n}\n"
  },
  {
    "path": "ext/openssl/ossl_x509req.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewX509Req(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509req_type, 0)\n#define SetX509Req(obj, req) do { \\\n    if (!(req)) { \\\n        ossl_raise(rb_eRuntimeError, \"Req wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (req); \\\n} while (0)\n#define GetX509Req(obj, req) do { \\\n    TypedData_Get_Struct((obj), X509_REQ, &ossl_x509req_type, (req)); \\\n    if (!(req)) { \\\n        ossl_raise(rb_eRuntimeError, \"Req wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nstatic VALUE cX509Req;\nstatic VALUE eX509ReqError;\n\nstatic void\nossl_x509req_free(void *ptr)\n{\n    X509_REQ_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_x509req_type = {\n    \"OpenSSL/X509/REQ\",\n    {\n        0, ossl_x509req_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Public functions\n */\nX509_REQ *\nGetX509ReqPtr(VALUE obj)\n{\n    X509_REQ *req;\n\n    GetX509Req(obj, req);\n\n    return req;\n}\n\n/*\n * Private functions\n */\nstatic VALUE\nossl_x509req_alloc(VALUE klass)\n{\n    X509_REQ *req;\n    VALUE obj;\n\n    obj = NewX509Req(klass);\n    if (!(req = X509_REQ_new())) {\n        ossl_raise(eX509ReqError, NULL);\n    }\n    SetX509Req(obj, req);\n\n    return obj;\n}\n\nstatic VALUE\nossl_x509req_initialize(int argc, VALUE *argv, VALUE self)\n{\n    BIO *in;\n    X509_REQ *req, *req_orig = RTYPEDDATA_DATA(self);\n    VALUE arg;\n\n    rb_check_frozen(self);\n    if (rb_scan_args(argc, argv, \"01\", &arg) == 0) {\n        return self;\n    }\n    arg = ossl_to_der_if_possible(arg);\n    in = ossl_obj2bio(&arg);\n    req = d2i_X509_REQ_bio(in, NULL);\n    if (!req) {\n        OSSL_BIO_reset(in);\n        req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);\n    }\n    BIO_free(in);\n    if (!req)\n        ossl_raise(eX509ReqError, \"PEM_read_bio_X509_REQ\");\n\n    RTYPEDDATA_DATA(self) = req;\n    X509_REQ_free(req_orig);\n\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_x509req_copy(VALUE self, VALUE other)\n{\n    X509_REQ *a, *b, *req;\n\n    rb_check_frozen(self);\n    if (self == other) return self;\n    GetX509Req(self, a);\n    GetX509Req(other, b);\n    if (!(req = X509_REQ_dup(b))) {\n        ossl_raise(eX509ReqError, NULL);\n    }\n    X509_REQ_free(a);\n    DATA_PTR(self) = req;\n\n    return self;\n}\n\nstatic VALUE\nossl_x509req_to_pem(VALUE self)\n{\n    X509_REQ *req;\n    BIO *out;\n\n    GetX509Req(self, req);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eX509ReqError, NULL);\n    }\n    if (!PEM_write_bio_X509_REQ(out, req)) {\n        BIO_free(out);\n        ossl_raise(eX509ReqError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\nstatic VALUE\nossl_x509req_to_der(VALUE self)\n{\n    X509_REQ *req;\n    VALUE str;\n    long len;\n    unsigned char *p;\n\n    GetX509Req(self, req);\n    if ((len = i2d_X509_REQ(req, NULL)) <= 0)\n        ossl_raise(eX509ReqError, NULL);\n    str = rb_str_new(0, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_X509_REQ(req, &p) <= 0)\n        ossl_raise(eX509ReqError, NULL);\n    ossl_str_adjust(str, p);\n\n    return str;\n}\n\nstatic VALUE\nossl_x509req_to_text(VALUE self)\n{\n    X509_REQ *req;\n    BIO *out;\n\n    GetX509Req(self, req);\n    if (!(out = BIO_new(BIO_s_mem()))) {\n        ossl_raise(eX509ReqError, NULL);\n    }\n    if (!X509_REQ_print(out, req)) {\n        BIO_free(out);\n        ossl_raise(eX509ReqError, NULL);\n    }\n\n    return ossl_membio2str(out);\n}\n\n#if 0\n/*\n * Makes X509 from X509_REQuest\n */\nstatic VALUE\nossl_x509req_to_x509(VALUE self, VALUE days, VALUE key)\n{\n    X509_REQ *req;\n    X509 *x509;\n\n    GetX509Req(self, req);\n    ...\n    if (!(x509 = X509_REQ_to_X509(req, d, pkey))) {\n        ossl_raise(eX509ReqError, NULL);\n    }\n\n    return ossl_x509_new(x509);\n}\n#endif\n\nstatic VALUE\nossl_x509req_get_version(VALUE self)\n{\n    X509_REQ *req;\n    long version;\n\n    GetX509Req(self, req);\n    version = X509_REQ_get_version(req);\n\n    return LONG2NUM(version);\n}\n\nstatic VALUE\nossl_x509req_set_version(VALUE self, VALUE version)\n{\n    X509_REQ *req;\n    long ver;\n\n    if ((ver = NUM2LONG(version)) < 0) {\n        ossl_raise(eX509ReqError, \"version must be >= 0!\");\n    }\n    GetX509Req(self, req);\n    if (!X509_REQ_set_version(req, ver)) {\n        ossl_raise(eX509ReqError, \"X509_REQ_set_version\");\n    }\n\n    return version;\n}\n\nstatic VALUE\nossl_x509req_get_subject(VALUE self)\n{\n    X509_REQ *req;\n    const X509_NAME *name;\n\n    GetX509Req(self, req);\n    if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */\n        ossl_raise(eX509ReqError, NULL);\n    }\n\n    return ossl_x509name_new(name);\n}\n\nstatic VALUE\nossl_x509req_set_subject(VALUE self, VALUE subject)\n{\n    X509_REQ *req;\n\n    GetX509Req(self, req);\n    /* DUPs name */\n    if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) {\n        ossl_raise(eX509ReqError, NULL);\n    }\n\n    return subject;\n}\n\n/*\n * call-seq:\n *    req.signature_algorithm -> string\n *\n * Returns the signature algorithm used to sign this request.\n *\n * Returns the long name of the signature algorithm, or the dotted decimal\n * notation if \\OpenSSL does not define a long name for it.\n */\nstatic VALUE\nossl_x509req_get_signature_algorithm(VALUE self)\n{\n    X509_REQ *req;\n    const X509_ALGOR *alg;\n    const ASN1_OBJECT *obj;\n\n    GetX509Req(self, req);\n    X509_REQ_get0_signature(req, NULL, &alg);\n    X509_ALGOR_get0(&obj, NULL, NULL, alg);\n    return ossl_asn1obj_to_string_long_name(obj);\n}\n\nstatic VALUE\nossl_x509req_get_public_key(VALUE self)\n{\n    X509_REQ *req;\n    EVP_PKEY *pkey;\n\n    GetX509Req(self, req);\n    if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */\n        ossl_raise(eX509ReqError, NULL);\n    }\n\n    return ossl_pkey_wrap(pkey);\n}\n\nstatic VALUE\nossl_x509req_set_public_key(VALUE self, VALUE key)\n{\n    X509_REQ *req;\n    EVP_PKEY *pkey;\n\n    GetX509Req(self, req);\n    pkey = GetPKeyPtr(key);\n    ossl_pkey_check_public_key(pkey);\n    if (!X509_REQ_set_pubkey(req, pkey))\n        ossl_raise(eX509ReqError, \"X509_REQ_set_pubkey\");\n    return key;\n}\n\nstatic VALUE\nossl_x509req_sign(VALUE self, VALUE key, VALUE digest)\n{\n    X509_REQ *req;\n    EVP_PKEY *pkey;\n    const EVP_MD *md;\n    VALUE md_holder;\n\n    GetX509Req(self, req);\n    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */\n    /* NULL needed for some key types, e.g. Ed25519 */\n    md = NIL_P(digest) ? NULL : ossl_evp_md_fetch(digest, &md_holder);\n    if (!X509_REQ_sign(req, pkey, md))\n        ossl_raise(eX509ReqError, \"X509_REQ_sign\");\n\n    return self;\n}\n\n/*\n * Checks that cert signature is made with PRIVversion of this PUBLIC 'key'\n */\nstatic VALUE\nossl_x509req_verify(VALUE self, VALUE key)\n{\n    X509_REQ *req;\n    EVP_PKEY *pkey;\n\n    GetX509Req(self, req);\n    pkey = GetPKeyPtr(key);\n    ossl_pkey_check_public_key(pkey);\n    switch (X509_REQ_verify(req, pkey)) {\n      case 1:\n        return Qtrue;\n      case 0:\n        ossl_clear_error();\n        return Qfalse;\n      default:\n        ossl_raise(eX509ReqError, NULL);\n    }\n}\n\nstatic VALUE\nossl_x509req_get_attributes(VALUE self)\n{\n    X509_REQ *req;\n    int count, i;\n    const X509_ATTRIBUTE *attr;\n    VALUE ary;\n\n    GetX509Req(self, req);\n\n    count = X509_REQ_get_attr_count(req);\n    if (count < 0) {\n        OSSL_Debug(\"count < 0???\");\n        return rb_ary_new();\n    }\n    ary = rb_ary_new2(count);\n    for (i=0; i<count; i++) {\n        attr = X509_REQ_get_attr(req, i);\n        rb_ary_push(ary, ossl_x509attr_new(attr));\n    }\n\n    return ary;\n}\n\nstatic VALUE\nossl_x509req_set_attributes(VALUE self, VALUE ary)\n{\n    X509_REQ *req;\n    X509_ATTRIBUTE *attr;\n    long i;\n    VALUE item;\n\n    Check_Type(ary, T_ARRAY);\n    for (i=0;i<RARRAY_LEN(ary); i++) {\n        OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Attr);\n    }\n    GetX509Req(self, req);\n    for (i = X509_REQ_get_attr_count(req); i > 0; i--)\n        X509_ATTRIBUTE_free(X509_REQ_delete_attr(req, 0));\n    for (i=0;i<RARRAY_LEN(ary); i++) {\n        item = RARRAY_AREF(ary, i);\n        attr = GetX509AttrPtr(item);\n        if (!X509_REQ_add1_attr(req, attr)) {\n            ossl_raise(eX509ReqError, \"X509_REQ_add1_attr\");\n        }\n    }\n    return ary;\n}\n\nstatic VALUE\nossl_x509req_add_attribute(VALUE self, VALUE attr)\n{\n    X509_REQ *req;\n\n    GetX509Req(self, req);\n    if (!X509_REQ_add1_attr(req, GetX509AttrPtr(attr))) {\n        ossl_raise(eX509ReqError, NULL);\n    }\n\n    return attr;\n}\n\n/*\n * X509_REQUEST init\n */\nvoid\nInit_ossl_x509req(void)\n{\n    eX509ReqError = rb_define_class_under(mX509, \"RequestError\", eOSSLError);\n\n    cX509Req = rb_define_class_under(mX509, \"Request\", rb_cObject);\n\n    rb_define_alloc_func(cX509Req, ossl_x509req_alloc);\n    rb_define_method(cX509Req, \"initialize\", ossl_x509req_initialize, -1);\n    rb_define_method(cX509Req, \"initialize_copy\", ossl_x509req_copy, 1);\n\n    rb_define_method(cX509Req, \"to_pem\", ossl_x509req_to_pem, 0);\n    rb_define_method(cX509Req, \"to_der\", ossl_x509req_to_der, 0);\n    rb_define_alias(cX509Req, \"to_s\", \"to_pem\");\n    rb_define_method(cX509Req, \"to_text\", ossl_x509req_to_text, 0);\n    rb_define_method(cX509Req, \"version\", ossl_x509req_get_version, 0);\n    rb_define_method(cX509Req, \"version=\", ossl_x509req_set_version, 1);\n    rb_define_method(cX509Req, \"subject\", ossl_x509req_get_subject, 0);\n    rb_define_method(cX509Req, \"subject=\", ossl_x509req_set_subject, 1);\n    rb_define_method(cX509Req, \"signature_algorithm\", ossl_x509req_get_signature_algorithm, 0);\n    rb_define_method(cX509Req, \"public_key\", ossl_x509req_get_public_key, 0);\n    rb_define_method(cX509Req, \"public_key=\", ossl_x509req_set_public_key, 1);\n    rb_define_method(cX509Req, \"sign\", ossl_x509req_sign, 2);\n    rb_define_method(cX509Req, \"verify\", ossl_x509req_verify, 1);\n    rb_define_method(cX509Req, \"attributes\", ossl_x509req_get_attributes, 0);\n    rb_define_method(cX509Req, \"attributes=\", ossl_x509req_set_attributes, 1);\n    rb_define_method(cX509Req, \"add_attribute\", ossl_x509req_add_attribute, 1);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_x509revoked.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewX509Rev(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509rev_type, 0)\n#define SetX509Rev(obj, rev) do { \\\n    if (!(rev)) { \\\n        ossl_raise(rb_eRuntimeError, \"REV wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (rev); \\\n} while (0)\n#define GetX509Rev(obj, rev) do { \\\n    TypedData_Get_Struct((obj), X509_REVOKED, &ossl_x509rev_type, (rev)); \\\n    if (!(rev)) { \\\n        ossl_raise(rb_eRuntimeError, \"REV wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n/*\n * Classes\n */\nVALUE cX509Rev;\nstatic VALUE eX509RevError;\n\nstatic void\nossl_x509rev_free(void *ptr)\n{\n    X509_REVOKED_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_x509rev_type = {\n    \"OpenSSL/X509/REV\",\n    {\n        0, ossl_x509rev_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * PUBLIC\n */\nVALUE\nossl_x509revoked_new(const X509_REVOKED *rev)\n{\n    X509_REVOKED *new;\n    VALUE obj;\n\n    obj = NewX509Rev(cX509Rev);\n    /* OpenSSL 1.1.1 takes a non-const pointer */\n    new = X509_REVOKED_dup((X509_REVOKED *)rev);\n    if (!new)\n        ossl_raise(eX509RevError, \"X509_REVOKED_dup\");\n    SetX509Rev(obj, new);\n\n    return obj;\n}\n\nX509_REVOKED *\nDupX509RevokedPtr(VALUE obj)\n{\n    X509_REVOKED *rev, *new;\n\n    GetX509Rev(obj, rev);\n    if (!(new = X509_REVOKED_dup(rev))) {\n        ossl_raise(eX509RevError, NULL);\n    }\n\n    return new;\n}\n\n/*\n * PRIVATE\n */\nstatic VALUE\nossl_x509revoked_alloc(VALUE klass)\n{\n    X509_REVOKED *rev;\n    VALUE obj;\n\n    obj = NewX509Rev(klass);\n    if (!(rev = X509_REVOKED_new())) {\n        ossl_raise(eX509RevError, NULL);\n    }\n    SetX509Rev(obj, rev);\n\n    return obj;\n}\n\nstatic VALUE\nossl_x509revoked_initialize(int argc, VALUE *argv, VALUE self)\n{\n    /* EMPTY */\n    return self;\n}\n\n/* :nodoc: */\nstatic VALUE\nossl_x509revoked_initialize_copy(VALUE self, VALUE other)\n{\n    X509_REVOKED *rev, *rev_other, *rev_new;\n\n    rb_check_frozen(self);\n    GetX509Rev(self, rev);\n    GetX509Rev(other, rev_other);\n\n    rev_new = X509_REVOKED_dup(rev_other);\n    if (!rev_new)\n        ossl_raise(eX509RevError, \"X509_REVOKED_dup\");\n\n    SetX509Rev(self, rev_new);\n    X509_REVOKED_free(rev);\n\n    return self;\n}\n\nstatic VALUE\nossl_x509revoked_get_serial(VALUE self)\n{\n    X509_REVOKED *rev;\n\n    GetX509Rev(self, rev);\n\n    return asn1integer_to_num(X509_REVOKED_get0_serialNumber(rev));\n}\n\nstatic VALUE\nossl_x509revoked_set_serial(VALUE self, VALUE num)\n{\n    X509_REVOKED *rev;\n    ASN1_INTEGER *asn1int;\n\n    GetX509Rev(self, rev);\n    asn1int = num_to_asn1integer(num, NULL);\n    if (!X509_REVOKED_set_serialNumber(rev, asn1int)) {\n        ASN1_INTEGER_free(asn1int);\n        ossl_raise(eX509RevError, \"X509_REVOKED_set_serialNumber\");\n    }\n    ASN1_INTEGER_free(asn1int);\n\n    return num;\n}\n\nstatic VALUE\nossl_x509revoked_get_time(VALUE self)\n{\n    X509_REVOKED *rev;\n    const ASN1_TIME *time;\n\n    GetX509Rev(self, rev);\n    time = X509_REVOKED_get0_revocationDate(rev);\n    if (!time)\n        return Qnil;\n\n    return asn1time_to_time(time);\n}\n\nstatic VALUE\nossl_x509revoked_set_time(VALUE self, VALUE time)\n{\n    X509_REVOKED *rev;\n    ASN1_TIME *asn1time;\n\n    GetX509Rev(self, rev);\n    asn1time = ossl_x509_time_adjust(NULL, time);\n    if (!X509_REVOKED_set_revocationDate(rev, asn1time)) {\n        ASN1_TIME_free(asn1time);\n        ossl_raise(eX509RevError, \"X509_REVOKED_set_revocationDate\");\n    }\n    ASN1_TIME_free(asn1time);\n\n    return time;\n}\n/*\n * Gets X509v3 extensions as array of X509Ext objects\n */\nstatic VALUE\nossl_x509revoked_get_extensions(VALUE self)\n{\n    X509_REVOKED *rev;\n    int count, i;\n    const X509_EXTENSION *ext;\n    VALUE ary;\n\n    GetX509Rev(self, rev);\n    count = X509_REVOKED_get_ext_count(rev);\n    ary = rb_ary_new_capa(count);\n    for (i=0; i<count; i++) {\n        ext = X509_REVOKED_get_ext(rev, i);\n        rb_ary_push(ary, ossl_x509ext_new(ext));\n    }\n\n    return ary;\n}\n\n/*\n * Sets X509_EXTENSIONs\n */\nstatic VALUE\nossl_x509revoked_set_extensions(VALUE self, VALUE ary)\n{\n    X509_REVOKED *rev;\n    X509_EXTENSION *ext;\n    long i;\n    VALUE item;\n\n    Check_Type(ary, T_ARRAY);\n    for (i=0; i<RARRAY_LEN(ary); i++) {\n        OSSL_Check_Kind(RARRAY_AREF(ary, i), cX509Ext);\n    }\n    GetX509Rev(self, rev);\n    for (i = X509_REVOKED_get_ext_count(rev); i > 0; i--)\n        X509_EXTENSION_free(X509_REVOKED_delete_ext(rev, 0));\n    for (i=0; i<RARRAY_LEN(ary); i++) {\n        item = RARRAY_AREF(ary, i);\n        ext = GetX509ExtPtr(item);\n        if(!X509_REVOKED_add_ext(rev, ext, -1)) {\n            ossl_raise(eX509RevError, \"X509_REVOKED_add_ext\");\n        }\n    }\n\n    return ary;\n}\n\nstatic VALUE\nossl_x509revoked_add_extension(VALUE self, VALUE ext)\n{\n    X509_REVOKED *rev;\n\n    GetX509Rev(self, rev);\n    if (!X509_REVOKED_add_ext(rev, GetX509ExtPtr(ext), -1)) {\n        ossl_raise(eX509RevError, NULL);\n    }\n\n    return ext;\n}\n\nstatic VALUE\nossl_x509revoked_to_der(VALUE self)\n{\n    X509_REVOKED *rev;\n    VALUE str;\n    int len;\n    unsigned char *p;\n\n    GetX509Rev(self, rev);\n    len = i2d_X509_REVOKED(rev, NULL);\n    if (len <= 0)\n        ossl_raise(eX509RevError, \"i2d_X509_REVOKED\");\n    str = rb_str_new(NULL, len);\n    p = (unsigned char *)RSTRING_PTR(str);\n    if (i2d_X509_REVOKED(rev, &p) <= 0)\n        ossl_raise(eX509RevError, \"i2d_X509_REVOKED\");\n    ossl_str_adjust(str, p);\n    return str;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_x509revoked(void)\n{\n    eX509RevError = rb_define_class_under(mX509, \"RevokedError\", eOSSLError);\n\n    cX509Rev = rb_define_class_under(mX509, \"Revoked\", rb_cObject);\n\n    rb_define_alloc_func(cX509Rev, ossl_x509revoked_alloc);\n    rb_define_method(cX509Rev, \"initialize\", ossl_x509revoked_initialize, -1);\n    rb_define_method(cX509Rev, \"initialize_copy\", ossl_x509revoked_initialize_copy, 1);\n\n    rb_define_method(cX509Rev, \"serial\", ossl_x509revoked_get_serial, 0);\n    rb_define_method(cX509Rev, \"serial=\", ossl_x509revoked_set_serial, 1);\n    rb_define_method(cX509Rev, \"time\", ossl_x509revoked_get_time, 0);\n    rb_define_method(cX509Rev, \"time=\", ossl_x509revoked_set_time, 1);\n    rb_define_method(cX509Rev, \"extensions\", ossl_x509revoked_get_extensions, 0);\n    rb_define_method(cX509Rev, \"extensions=\", ossl_x509revoked_set_extensions, 1);\n    rb_define_method(cX509Rev, \"add_extension\", ossl_x509revoked_add_extension, 1);\n    rb_define_method(cX509Rev, \"to_der\", ossl_x509revoked_to_der, 0);\n}\n"
  },
  {
    "path": "ext/openssl/ossl_x509store.c",
    "content": "/*\n * 'OpenSSL for Ruby' project\n * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>\n * All rights reserved.\n */\n/*\n * This program is licensed under the same licence as Ruby.\n * (See the file 'COPYING'.)\n */\n#include \"ossl.h\"\n\n#define NewX509Store(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509store_type, 0)\n#define SetX509Store(obj, st) do { \\\n    if (!(st)) { \\\n        ossl_raise(rb_eRuntimeError, \"STORE wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (st); \\\n} while (0)\n#define GetX509Store(obj, st) do { \\\n    TypedData_Get_Struct((obj), X509_STORE, &ossl_x509store_type, (st)); \\\n    if (!(st)) { \\\n        ossl_raise(rb_eRuntimeError, \"STORE wasn't initialized!\"); \\\n    } \\\n} while (0)\n\n#define NewX509StCtx(klass) \\\n    TypedData_Wrap_Struct((klass), &ossl_x509stctx_type, 0)\n#define SetX509StCtx(obj, ctx) do { \\\n    if (!(ctx)) { \\\n        ossl_raise(rb_eRuntimeError, \"STORE_CTX wasn't initialized!\"); \\\n    } \\\n    RTYPEDDATA_DATA(obj) = (ctx); \\\n} while (0)\n#define GetX509StCtx(obj, ctx) do { \\\n    TypedData_Get_Struct((obj), X509_STORE_CTX, &ossl_x509stctx_type, (ctx)); \\\n    if (!(ctx)) { \\\n        ossl_raise(rb_eRuntimeError, \"STORE_CTX is out of scope!\"); \\\n    } \\\n} while (0)\n\n/*\n * Verify callback stuff\n */\nstatic int stctx_ex_verify_cb_idx, store_ex_verify_cb_idx;\nstatic VALUE ossl_x509stctx_new(X509_STORE_CTX *);\n\nstruct ossl_verify_cb_args {\n    VALUE proc;\n    VALUE preverify_ok;\n    VALUE store_ctx;\n};\n\nstatic VALUE\nossl_x509stctx_new_i(VALUE arg)\n{\n    return ossl_x509stctx_new((X509_STORE_CTX *)arg);\n}\n\nstatic VALUE\ncall_verify_cb_proc(VALUE arg)\n{\n    struct ossl_verify_cb_args *args = (struct ossl_verify_cb_args *)arg;\n    return rb_funcall(args->proc, rb_intern(\"call\"), 2,\n                      args->preverify_ok, args->store_ctx);\n}\n\nint\nossl_verify_cb_call(VALUE proc, int ok, X509_STORE_CTX *ctx)\n{\n    VALUE rctx, ret;\n    struct ossl_verify_cb_args args;\n    int state;\n\n    if (NIL_P(proc))\n        return ok;\n\n    ret = Qfalse;\n    rctx = rb_protect(ossl_x509stctx_new_i, (VALUE)ctx, &state);\n    if (state) {\n        rb_set_errinfo(Qnil);\n        rb_warn(\"StoreContext initialization failure\");\n    }\n    else {\n        args.proc = proc;\n        args.preverify_ok = ok ? Qtrue : Qfalse;\n        args.store_ctx = rctx;\n        ret = rb_protect(call_verify_cb_proc, (VALUE)&args, &state);\n        if (state) {\n            rb_set_errinfo(Qnil);\n            rb_warn(\"exception in verify_callback is ignored\");\n        }\n        RTYPEDDATA_DATA(rctx) = NULL;\n    }\n    if (ret == Qtrue) {\n        X509_STORE_CTX_set_error(ctx, X509_V_OK);\n        ok = 1;\n    }\n    else {\n        if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)\n            X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);\n        ok = 0;\n    }\n\n    return ok;\n}\n\n/*\n * Classes\n */\nstatic VALUE cX509Store;\nstatic VALUE cX509StoreContext;\nstatic VALUE eX509StoreError;\n\nstatic void\nossl_x509store_mark(void *ptr)\n{\n    X509_STORE *store = ptr;\n    // Note: this reference is stored as @verify_callback so we don't need to mark it.\n    // However we do need to ensure GC compaction won't move it, hence why\n    // we call rb_gc_mark here.\n    rb_gc_mark((VALUE)X509_STORE_get_ex_data(store, store_ex_verify_cb_idx));\n}\n\nstatic void\nossl_x509store_free(void *ptr)\n{\n    X509_STORE_free(ptr);\n}\n\nstatic const rb_data_type_t ossl_x509store_type = {\n    \"OpenSSL/X509/STORE\",\n    {\n        ossl_x509store_mark, ossl_x509store_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\n/*\n * Public functions\n */\nX509_STORE *\nGetX509StorePtr(VALUE obj)\n{\n    X509_STORE *store;\n\n    GetX509Store(obj, store);\n\n    return store;\n}\n\n/*\n * Private functions\n */\nstatic int\nx509store_verify_cb(int ok, X509_STORE_CTX *ctx)\n{\n    VALUE proc;\n\n    proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx);\n    if (!proc)\n        proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx),\n                                             store_ex_verify_cb_idx);\n    if (!proc)\n        return ok;\n\n    return ossl_verify_cb_call(proc, ok, ctx);\n}\n\nstatic VALUE\nossl_x509store_alloc(VALUE klass)\n{\n    X509_STORE *store;\n    VALUE obj;\n\n    obj = NewX509Store(klass);\n    if ((store = X509_STORE_new()) == NULL)\n        ossl_raise(eX509StoreError, \"X509_STORE_new\");\n    SetX509Store(obj, store);\n\n    return obj;\n}\n\n/*\n * General callback for OpenSSL verify\n */\nstatic VALUE\nossl_x509store_set_vfy_cb(VALUE self, VALUE cb)\n{\n    X509_STORE *store;\n\n    GetX509Store(self, store);\n    if (!X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb))\n        ossl_raise(eX509StoreError, \"X509_STORE_set_ex_data\");\n    rb_iv_set(self, \"@verify_callback\", cb);\n    RB_OBJ_WRITTEN(self, Qundef, cb);\n\n    return cb;\n}\n\n\n/*\n * call-seq:\n *    X509::Store.new => store\n *\n * Creates a new X509::Store.\n */\nstatic VALUE\nossl_x509store_initialize(int argc, VALUE *argv, VALUE self)\n{\n    X509_STORE *store;\n\n    GetX509Store(self, store);\n    if (argc != 0)\n        rb_warn(\"OpenSSL::X509::Store.new does not take any arguments\");\n    X509_STORE_set_verify_cb(store, x509store_verify_cb);\n    ossl_x509store_set_vfy_cb(self, Qnil);\n\n    /* last verification status */\n    rb_iv_set(self, \"@error\", Qnil);\n    rb_iv_set(self, \"@error_string\", Qnil);\n    rb_iv_set(self, \"@chain\", Qnil);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   store.flags = flags\n *\n * Sets the default flags used by certificate chain verification performed with\n * the Store.\n *\n * _flags_ consists of zero or more of the constants defined in OpenSSL::X509\n * with name V_FLAG_* or'ed together.\n *\n * OpenSSL::X509::StoreContext#flags= can be used to change the flags for a\n * single verification operation.\n *\n * See also the man page X509_VERIFY_PARAM_set_flags(3).\n */\nstatic VALUE\nossl_x509store_set_flags(VALUE self, VALUE flags)\n{\n    X509_STORE *store;\n    long f = NUM2LONG(flags);\n\n    GetX509Store(self, store);\n    X509_STORE_set_flags(store, f);\n\n    return flags;\n}\n\n/*\n * call-seq:\n *   store.purpose = purpose\n *\n * Sets the store's default verification purpose. If specified,\n * the verifications on the store will check every certificate's extensions are\n * consistent with the purpose. The purpose is specified by constants:\n *\n * * X509::PURPOSE_SSL_CLIENT\n * * X509::PURPOSE_SSL_SERVER\n * * X509::PURPOSE_NS_SSL_SERVER\n * * X509::PURPOSE_SMIME_SIGN\n * * X509::PURPOSE_SMIME_ENCRYPT\n * * X509::PURPOSE_CRL_SIGN\n * * X509::PURPOSE_ANY\n * * X509::PURPOSE_OCSP_HELPER\n * * X509::PURPOSE_TIMESTAMP_SIGN\n *\n * OpenSSL::X509::StoreContext#purpose= can be used to change the value for a\n * single verification operation.\n *\n * See also the man page X509_VERIFY_PARAM_set_purpose(3).\n */\nstatic VALUE\nossl_x509store_set_purpose(VALUE self, VALUE purpose)\n{\n    X509_STORE *store;\n    int p = NUM2INT(purpose);\n\n    GetX509Store(self, store);\n    X509_STORE_set_purpose(store, p);\n\n    return purpose;\n}\n\n/*\n * call-seq:\n *   store.trust = trust\n *\n * Sets the default trust settings used by the certificate verification with\n * the store.\n *\n * OpenSSL::X509::StoreContext#trust= can be used to change the value for a\n * single verification operation.\n *\n * See also the man page X509_VERIFY_PARAM_set_trust(3).\n */\nstatic VALUE\nossl_x509store_set_trust(VALUE self, VALUE trust)\n{\n    X509_STORE *store;\n    int t = NUM2INT(trust);\n\n    GetX509Store(self, store);\n    X509_STORE_set_trust(store, t);\n\n    return trust;\n}\n\n/*\n * call-seq:\n *   store.time = time\n *\n * Sets the time to be used in the certificate verifications with the store.\n * By default, if not specified, the current system time is used.\n *\n * OpenSSL::X509::StoreContext#time= can be used to change the value for a\n * single verification operation.\n *\n * See also the man page X509_VERIFY_PARAM_set_time(3).\n */\nstatic VALUE\nossl_x509store_set_time(VALUE self, VALUE time)\n{\n    X509_STORE *store;\n    X509_VERIFY_PARAM *param;\n\n    GetX509Store(self, store);\n    param = X509_STORE_get0_param(store);\n    X509_VERIFY_PARAM_set_time(param, NUM2LONG(rb_Integer(time)));\n    return time;\n}\n\n/*\n * call-seq:\n *   store.add_file(file) -> self\n *\n * Adds the certificates in _file_ to the certificate store. _file_ is the path\n * to the file, and the file contains one or more certificates in PEM format\n * concatenated together.\n *\n * See also the man page X509_LOOKUP_file(3).\n */\nstatic VALUE\nossl_x509store_add_file(VALUE self, VALUE file)\n{\n    X509_STORE *store;\n    X509_LOOKUP *lookup;\n    const char *path;\n\n    GetX509Store(self, store);\n    path = StringValueCStr(file);\n    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());\n    if (!lookup)\n        ossl_raise(eX509StoreError, \"X509_STORE_add_lookup\");\n    if (X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1)\n        ossl_raise(eX509StoreError, \"X509_LOOKUP_load_file\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *   store.add_path(path) -> self\n *\n * Adds _path_ as the hash dir to be looked up by the store.\n *\n * See also the man page X509_LOOKUP_hash_dir(3).\n */\nstatic VALUE\nossl_x509store_add_path(VALUE self, VALUE dir)\n{\n    X509_STORE *store;\n    X509_LOOKUP *lookup;\n    const char *path;\n\n    GetX509Store(self, store);\n    path = StringValueCStr(dir);\n    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());\n    if (!lookup)\n        ossl_raise(eX509StoreError, \"X509_STORE_add_lookup\");\n    if (X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1)\n        ossl_raise(eX509StoreError, \"X509_LOOKUP_add_dir\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *   store.set_default_paths\n *\n * Configures _store_ to look up CA certificates from the system default\n * certificate store as needed basis. The location of the store can usually be\n * determined by:\n *\n * * OpenSSL::X509::DEFAULT_CERT_FILE\n * * OpenSSL::X509::DEFAULT_CERT_DIR\n *\n * See also the man page X509_STORE_set_default_paths(3).\n */\nstatic VALUE\nossl_x509store_set_default_paths(VALUE self)\n{\n    X509_STORE *store;\n\n    GetX509Store(self, store);\n    if (X509_STORE_set_default_paths(store) != 1)\n        ossl_raise(eX509StoreError, \"X509_STORE_set_default_paths\");\n\n    return Qnil;\n}\n\n/*\n * call-seq:\n *   store.add_cert(cert) -> self\n *\n * Adds the OpenSSL::X509::Certificate _cert_ to the certificate store.\n *\n * See also the man page X509_STORE_add_cert(3).\n */\nstatic VALUE\nossl_x509store_add_cert(VALUE self, VALUE arg)\n{\n    X509_STORE *store;\n    X509 *cert;\n\n    cert = GetX509CertPtr(arg); /* NO NEED TO DUP */\n    GetX509Store(self, store);\n    if (X509_STORE_add_cert(store, cert) != 1)\n        ossl_raise(eX509StoreError, \"X509_STORE_add_cert\");\n\n    return self;\n}\n\n/*\n * call-seq:\n *   store.add_crl(crl) -> self\n *\n * Adds the OpenSSL::X509::CRL _crl_ to the store.\n *\n * See also the man page X509_STORE_add_crl(3).\n */\nstatic VALUE\nossl_x509store_add_crl(VALUE self, VALUE arg)\n{\n    X509_STORE *store;\n    X509_CRL *crl;\n\n    crl = GetX509CRLPtr(arg); /* NO NEED TO DUP */\n    GetX509Store(self, store);\n    if (X509_STORE_add_crl(store, crl) != 1)\n        ossl_raise(eX509StoreError, \"X509_STORE_add_crl\");\n\n    return self;\n}\n\nstatic VALUE ossl_x509stctx_get_err(VALUE);\nstatic VALUE ossl_x509stctx_get_err_string(VALUE);\nstatic VALUE ossl_x509stctx_get_chain(VALUE);\n\n/*\n * call-seq:\n *   store.verify(cert, chain = nil) -> true | false\n *\n * Performs a certificate verification on the OpenSSL::X509::Certificate _cert_.\n *\n * _chain_ can be an array of OpenSSL::X509::Certificate that is used to\n * construct the certificate chain.\n *\n * If a block is given, it overrides the callback set by #verify_callback=.\n *\n * After finishing the verification, the error information can be retrieved by\n * #error, #error_string, and the resulting complete certificate chain can be\n * retrieved by #chain.\n */\nstatic VALUE\nossl_x509store_verify(int argc, VALUE *argv, VALUE self)\n{\n    VALUE cert, chain;\n    VALUE ctx, proc, result;\n\n    rb_scan_args(argc, argv, \"11\", &cert, &chain);\n    ctx = rb_funcall(cX509StoreContext, rb_intern(\"new\"), 3, self, cert, chain);\n    proc = rb_block_given_p() ?  rb_block_proc() :\n           rb_iv_get(self, \"@verify_callback\");\n    rb_iv_set(ctx, \"@verify_callback\", proc);\n    result = rb_funcall(ctx, rb_intern(\"verify\"), 0);\n\n    rb_iv_set(self, \"@error\", ossl_x509stctx_get_err(ctx));\n    rb_iv_set(self, \"@error_string\", ossl_x509stctx_get_err_string(ctx));\n    rb_iv_set(self, \"@chain\", ossl_x509stctx_get_chain(ctx));\n\n    return result;\n}\n\n/*\n * Private functions\n */\nstatic void\nossl_x509stctx_mark(void *ptr)\n{\n    X509_STORE_CTX *ctx = ptr;\n    // Note: this reference is stored as @verify_callback so we don't need to mark it.\n    // However we do need to ensure GC compaction won't move it, hence why\n    // we call rb_gc_mark here.\n    rb_gc_mark((VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx));\n}\n\nstatic void\nossl_x509stctx_free(void *ptr)\n{\n    X509_STORE_CTX *ctx = ptr;\n    sk_X509_pop_free(X509_STORE_CTX_get0_untrusted(ctx), X509_free);\n    X509_free((X509 *)X509_STORE_CTX_get0_cert(ctx));\n    X509_STORE_CTX_free(ctx);\n}\n\nstatic const rb_data_type_t ossl_x509stctx_type = {\n    \"OpenSSL/X509/STORE_CTX\",\n    {\n        ossl_x509stctx_mark, ossl_x509stctx_free,\n    },\n    0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,\n};\n\nstatic VALUE\nossl_x509stctx_alloc(VALUE klass)\n{\n    X509_STORE_CTX *ctx;\n    VALUE obj;\n\n    obj = NewX509StCtx(klass);\n    if ((ctx = X509_STORE_CTX_new()) == NULL)\n        ossl_raise(eX509StoreError, \"X509_STORE_CTX_new\");\n    SetX509StCtx(obj, ctx);\n\n    return obj;\n}\n\nstatic VALUE\nossl_x509stctx_new(X509_STORE_CTX *ctx)\n{\n    VALUE obj;\n\n    obj = NewX509StCtx(cX509StoreContext);\n    SetX509StCtx(obj, ctx);\n\n    return obj;\n}\n\nstatic VALUE ossl_x509stctx_set_flags(VALUE, VALUE);\nstatic VALUE ossl_x509stctx_set_purpose(VALUE, VALUE);\nstatic VALUE ossl_x509stctx_set_trust(VALUE, VALUE);\n\n/*\n * call-seq:\n *   StoreContext.new(store, cert = nil, untrusted = nil)\n *\n * Sets up a StoreContext for a verification of the X.509 certificate _cert_.\n */\nstatic VALUE\nossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self)\n{\n    VALUE store, cert, chain;\n    X509_STORE_CTX *ctx;\n    X509_STORE *x509st;\n    X509 *x509 = NULL;\n    STACK_OF(X509) *x509s = NULL;\n    int state;\n\n    rb_scan_args(argc, argv, \"12\", &store, &cert, &chain);\n    GetX509StCtx(self, ctx);\n    GetX509Store(store, x509st);\n    if (!NIL_P(cert))\n        x509 = DupX509CertPtr(cert); /* NEED TO DUP */\n    if (!NIL_P(chain)) {\n        x509s = ossl_protect_x509_ary2sk(chain, &state);\n        if (state) {\n            X509_free(x509);\n            rb_jump_tag(state);\n        }\n    }\n    if (X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){\n        X509_free(x509);\n        sk_X509_pop_free(x509s, X509_free);\n        ossl_raise(eX509StoreError, \"X509_STORE_CTX_init\");\n    }\n    rb_iv_set(self, \"@verify_callback\", rb_iv_get(store, \"@verify_callback\"));\n    rb_iv_set(self, \"@cert\", cert);\n\n    return self;\n}\n\n/*\n * call-seq:\n *   stctx.verify -> true | false\n *\n * Performs the certificate verification using the parameters set to _stctx_.\n *\n * See also the man page X509_verify_cert(3).\n */\nstatic VALUE\nossl_x509stctx_verify(VALUE self)\n{\n    X509_STORE_CTX *ctx;\n\n    GetX509StCtx(self, ctx);\n    VALUE cb = rb_iv_get(self, \"@verify_callback\");\n    if (!X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)cb))\n        ossl_raise(eX509StoreError, \"X509_STORE_CTX_set_ex_data\");\n    RB_OBJ_WRITTEN(self, Qundef, cb);\n\n    switch (X509_verify_cert(ctx)) {\n      case 1:\n        return Qtrue;\n      case 0:\n        ossl_clear_error();\n        return Qfalse;\n      default:\n        ossl_raise(eX509StoreError, \"X509_verify_cert\");\n    }\n}\n\n/*\n * call-seq:\n *   stctx.chain -> nil | Array of X509::Certificate\n *\n * Returns the verified chain.\n *\n * See also the man page X509_STORE_CTX_set0_verified_chain(3).\n */\nstatic VALUE\nossl_x509stctx_get_chain(VALUE self)\n{\n    X509_STORE_CTX *ctx;\n    const STACK_OF(X509) *chain;\n\n    GetX509StCtx(self, ctx);\n    chain = X509_STORE_CTX_get0_chain(ctx);\n    if (!chain)\n        return Qnil; /* Could be an empty array instead? */\n    return ossl_x509_sk2ary(chain);\n}\n\n/*\n * call-seq:\n *   stctx.error -> Integer\n *\n * Returns the error code of _stctx_. This is typically called after #verify\n * is done, or from the verification callback set to\n * OpenSSL::X509::Store#verify_callback=.\n *\n * See also the man page X509_STORE_CTX_get_error(3).\n */\nstatic VALUE\nossl_x509stctx_get_err(VALUE self)\n{\n    X509_STORE_CTX *ctx;\n\n    GetX509StCtx(self, ctx);\n\n    return INT2NUM(X509_STORE_CTX_get_error(ctx));\n}\n\n/*\n * call-seq:\n *   stctx.error = error_code\n *\n * Sets the error code of _stctx_. This is used by the verification callback\n * set to OpenSSL::X509::Store#verify_callback=.\n *\n * See also the man page X509_STORE_CTX_set_error(3).\n */\nstatic VALUE\nossl_x509stctx_set_error(VALUE self, VALUE err)\n{\n    X509_STORE_CTX *ctx;\n\n    GetX509StCtx(self, ctx);\n    X509_STORE_CTX_set_error(ctx, NUM2INT(err));\n\n    return err;\n}\n\n/*\n * call-seq:\n *   stctx.error_string -> String\n *\n * Returns the human readable error string corresponding to the error code\n * retrieved by #error.\n *\n * See also the man page X509_verify_cert_error_string(3).\n */\nstatic VALUE\nossl_x509stctx_get_err_string(VALUE self)\n{\n    X509_STORE_CTX *ctx;\n    long err;\n\n    GetX509StCtx(self, ctx);\n    err = X509_STORE_CTX_get_error(ctx);\n\n    return rb_str_new2(X509_verify_cert_error_string(err));\n}\n\n/*\n * call-seq:\n *   stctx.error_depth -> Integer\n *\n * Returns the depth of the chain. This is used in combination with #error.\n *\n * See also the man page X509_STORE_CTX_get_error_depth(3).\n */\nstatic VALUE\nossl_x509stctx_get_err_depth(VALUE self)\n{\n    X509_STORE_CTX *ctx;\n\n    GetX509StCtx(self, ctx);\n\n    return INT2NUM(X509_STORE_CTX_get_error_depth(ctx));\n}\n\n/*\n * call-seq:\n *   stctx.current_cert -> X509::Certificate\n *\n * Returns the certificate which caused the error.\n *\n * See also the man page X509_STORE_CTX_get_current_cert(3).\n */\nstatic VALUE\nossl_x509stctx_get_curr_cert(VALUE self)\n{\n    X509_STORE_CTX *ctx;\n    const X509 *x509;\n\n    GetX509StCtx(self, ctx);\n    x509 = X509_STORE_CTX_get_current_cert(ctx);\n    if (!x509)\n        return Qnil;\n\n    return ossl_x509_new(x509);\n}\n\n/*\n * call-seq:\n *   stctx.current_crl -> X509::CRL\n *\n * Returns the CRL which caused the error.\n *\n * See also the man page X509_STORE_CTX_get_current_crl(3).\n */\nstatic VALUE\nossl_x509stctx_get_curr_crl(VALUE self)\n{\n    X509_STORE_CTX *ctx;\n    const X509_CRL *crl;\n\n    GetX509StCtx(self, ctx);\n    crl = X509_STORE_CTX_get0_current_crl(ctx);\n    if (!crl)\n        return Qnil;\n\n    return ossl_x509crl_new(crl);\n}\n\n/*\n * call-seq:\n *   stctx.flags = flags\n *\n * Sets the verification flags to the context. This overrides the default value\n * set by Store#flags=.\n *\n * See also the man page X509_VERIFY_PARAM_set_flags(3).\n */\nstatic VALUE\nossl_x509stctx_set_flags(VALUE self, VALUE flags)\n{\n    X509_STORE_CTX *store;\n    long f = NUM2LONG(flags);\n\n    GetX509StCtx(self, store);\n    X509_STORE_CTX_set_flags(store, f);\n\n    return flags;\n}\n\n/*\n * call-seq:\n *   stctx.purpose = purpose\n *\n * Sets the purpose of the context. This overrides the default value set by\n * Store#purpose=.\n *\n * See also the man page X509_VERIFY_PARAM_set_purpose(3).\n */\nstatic VALUE\nossl_x509stctx_set_purpose(VALUE self, VALUE purpose)\n{\n    X509_STORE_CTX *store;\n    int p = NUM2INT(purpose);\n\n    GetX509StCtx(self, store);\n    X509_STORE_CTX_set_purpose(store, p);\n\n    return purpose;\n}\n\n/*\n * call-seq:\n *   stctx.trust = trust\n *\n * Sets the trust settings of the context. This overrides the default value set\n * by Store#trust=.\n *\n * See also the man page X509_VERIFY_PARAM_set_trust(3).\n */\nstatic VALUE\nossl_x509stctx_set_trust(VALUE self, VALUE trust)\n{\n    X509_STORE_CTX *store;\n    int t = NUM2INT(trust);\n\n    GetX509StCtx(self, store);\n    X509_STORE_CTX_set_trust(store, t);\n\n    return trust;\n}\n\n/*\n * call-seq:\n *   stctx.time = time\n *\n * Sets the time used in the verification. If not set, the current time is used.\n *\n * See also the man page X509_VERIFY_PARAM_set_time(3).\n */\nstatic VALUE\nossl_x509stctx_set_time(VALUE self, VALUE time)\n{\n    X509_STORE_CTX *store;\n    long t;\n\n    t = NUM2LONG(rb_Integer(time));\n    GetX509StCtx(self, store);\n    X509_STORE_CTX_set_time(store, 0, t);\n\n    return time;\n}\n\n/*\n * INIT\n */\nvoid\nInit_ossl_x509store(void)\n{\n#undef rb_intern\n    /* Register ext_data slot for verify callback Proc */\n    stctx_ex_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)\"stctx_ex_verify_cb_idx\", 0, 0, 0);\n    if (stctx_ex_verify_cb_idx < 0)\n        ossl_raise(eOSSLError, \"X509_STORE_CTX_get_ex_new_index\");\n    store_ex_verify_cb_idx = X509_STORE_get_ex_new_index(0, (void *)\"store_ex_verify_cb_idx\", 0, 0, 0);\n    if (store_ex_verify_cb_idx < 0)\n        ossl_raise(eOSSLError, \"X509_STORE_get_ex_new_index\");\n\n    eX509StoreError = rb_define_class_under(mX509, \"StoreError\", eOSSLError);\n\n    /* Document-class: OpenSSL::X509::Store\n     *\n     * The X509 certificate store holds trusted CA certificates used to verify\n     * peer certificates.\n     *\n     * The easiest way to create a useful certificate store is:\n     *\n     *   cert_store = OpenSSL::X509::Store.new\n     *   cert_store.set_default_paths\n     *\n     * This will use your system's built-in certificates.\n     *\n     * If your system does not have a default set of certificates you can obtain\n     * a set extracted from Mozilla CA certificate store by cURL maintainers\n     * here: https://curl.haxx.se/docs/caextract.html (You may wish to use the\n     * firefox-db2pem.sh script to extract the certificates from a local install\n     * to avoid man-in-the-middle attacks.)\n     *\n     * After downloading or generating a cacert.pem from the above link you\n     * can create a certificate store from the pem file like this:\n     *\n     *   cert_store = OpenSSL::X509::Store.new\n     *   cert_store.add_file 'cacert.pem'\n     *\n     * The certificate store can be used with an SSLSocket like this:\n     *\n     *   ssl_context = OpenSSL::SSL::SSLContext.new\n     *   ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER\n     *   ssl_context.cert_store = cert_store\n     *\n     *   tcp_socket = TCPSocket.open 'example.com', 443\n     *\n     *   ssl_socket = OpenSSL::SSL::SSLSocket.new tcp_socket, ssl_context\n     */\n\n    cX509Store = rb_define_class_under(mX509, \"Store\", rb_cObject);\n    /*\n     * The callback for additional certificate verification. It is invoked for\n     * each certificate in the chain and can be used to implement custom\n     * certificate verification conditions.\n     *\n     * The callback is invoked with two values, a boolean that indicates if the\n     * pre-verification by OpenSSL has succeeded or not, and the StoreContext in\n     * use.\n     *\n     * The callback can use StoreContext#error= to change the error code as\n     * needed. The callback must return either true or false.\n     *\n     * NOTE: any exception raised within the callback will be ignored.\n     *\n     * See also the man page X509_STORE_CTX_set_verify_cb(3).\n     */\n    rb_attr(cX509Store, rb_intern(\"verify_callback\"), 1, 0, Qfalse);\n    /*\n     * The error code set by the last call of #verify.\n     *\n     * See also StoreContext#error.\n     */\n    rb_attr(cX509Store, rb_intern(\"error\"), 1, 0, Qfalse);\n    /*\n     * The description for the error code set by the last call of #verify.\n     *\n     * See also StoreContext#error_string.\n     */\n    rb_attr(cX509Store, rb_intern(\"error_string\"), 1, 0, Qfalse);\n    /*\n     * The certificate chain constructed by the last call of #verify.\n     *\n     * See also StoreContext#chain.\n     */\n    rb_attr(cX509Store, rb_intern(\"chain\"), 1, 0, Qfalse);\n    rb_define_alloc_func(cX509Store, ossl_x509store_alloc);\n    rb_define_method(cX509Store, \"initialize\",   ossl_x509store_initialize, -1);\n    rb_undef_method(cX509Store, \"initialize_copy\");\n    rb_define_method(cX509Store, \"verify_callback=\", ossl_x509store_set_vfy_cb, 1);\n    rb_define_method(cX509Store, \"flags=\",       ossl_x509store_set_flags, 1);\n    rb_define_method(cX509Store, \"purpose=\",     ossl_x509store_set_purpose, 1);\n    rb_define_method(cX509Store, \"trust=\",       ossl_x509store_set_trust, 1);\n    rb_define_method(cX509Store, \"time=\",        ossl_x509store_set_time, 1);\n    rb_define_method(cX509Store, \"add_path\",     ossl_x509store_add_path, 1);\n    rb_define_method(cX509Store, \"add_file\",     ossl_x509store_add_file, 1);\n    rb_define_method(cX509Store, \"set_default_paths\", ossl_x509store_set_default_paths, 0);\n    rb_define_method(cX509Store, \"add_cert\",     ossl_x509store_add_cert, 1);\n    rb_define_method(cX509Store, \"add_crl\",      ossl_x509store_add_crl, 1);\n    rb_define_method(cX509Store, \"verify\",       ossl_x509store_verify, -1);\n\n    /*\n     * Document-class: OpenSSL::X509::StoreContext\n     *\n     * A StoreContext is used while validating a single certificate and holds\n     * the status involved.\n     */\n    cX509StoreContext = rb_define_class_under(mX509,\"StoreContext\", rb_cObject);\n    rb_define_alloc_func(cX509StoreContext, ossl_x509stctx_alloc);\n    rb_define_method(cX509StoreContext, \"initialize\", ossl_x509stctx_initialize, -1);\n    rb_undef_method(cX509StoreContext, \"initialize_copy\");\n    rb_define_method(cX509StoreContext, \"verify\", ossl_x509stctx_verify, 0);\n    rb_define_method(cX509StoreContext, \"chain\", ossl_x509stctx_get_chain,0);\n    rb_define_method(cX509StoreContext, \"error\", ossl_x509stctx_get_err, 0);\n    rb_define_method(cX509StoreContext, \"error=\", ossl_x509stctx_set_error, 1);\n    rb_define_method(cX509StoreContext, \"error_string\", ossl_x509stctx_get_err_string,0);\n    rb_define_method(cX509StoreContext, \"error_depth\", ossl_x509stctx_get_err_depth, 0);\n    rb_define_method(cX509StoreContext, \"current_cert\", ossl_x509stctx_get_curr_cert, 0);\n    rb_define_method(cX509StoreContext, \"current_crl\", ossl_x509stctx_get_curr_crl, 0);\n    rb_define_method(cX509StoreContext, \"flags=\", ossl_x509stctx_set_flags, 1);\n    rb_define_method(cX509StoreContext, \"purpose=\", ossl_x509stctx_set_purpose, 1);\n    rb_define_method(cX509StoreContext, \"trust=\", ossl_x509stctx_set_trust, 1);\n    rb_define_method(cX509StoreContext, \"time=\", ossl_x509stctx_set_time, 1);\n}\n"
  },
  {
    "path": "lib/openssl/bn.rb",
    "content": "# frozen_string_literal: true\n#--\n#\n# = Ruby-space definitions that completes C-space funcs for BN\n#\n# = Info\n# 'OpenSSL for Ruby 2' project\n# Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>\n# All rights reserved.\n#\n# = Licence\n# This program is licensed under the same licence as Ruby.\n# (See the file 'COPYING'.)\n#++\n\nmodule OpenSSL\n  class BN\n    include Comparable\n\n    def pretty_print(q)\n      q.object_group(self) {\n        q.text ' '\n        q.text to_i.to_s\n      }\n    end\n  end # BN\nend # OpenSSL\n\n##\n#--\n# Add double dispatch to Integer\n#++\nclass Integer\n  # Casts an Integer as an OpenSSL::BN\n  #\n  # See `man bn` for more info.\n  def to_bn\n    OpenSSL::BN::new(self)\n  end\nend # Integer\n"
  },
  {
    "path": "lib/openssl/buffering.rb",
    "content": "# coding: binary\n# frozen_string_literal: true\n#--\n#= Info\n#  'OpenSSL for Ruby 2' project\n#  Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>\n#  All rights reserved.\n#\n#= Licence\n#  This program is licensed under the same licence as Ruby.\n#  (See the file 'COPYING'.)\n#++\n\n##\n# OpenSSL IO buffering mix-in module.\n#\n# This module allows an OpenSSL::SSL::SSLSocket to behave like an IO.\n#\n# You typically won't use this module directly, you can see it implemented in\n# OpenSSL::SSL::SSLSocket.\n\nmodule OpenSSL::Buffering\n  include Enumerable\n\n  # A buffer which will retain binary encoding.\n  class Buffer < String\n    unless String.method_defined?(:append_as_bytes)\n      alias_method :_append, :<<\n      def append_as_bytes(string)\n        if string.encoding == Encoding::BINARY\n          _append(string)\n        else\n          _append(string.b)\n        end\n\n        self\n      end\n    end\n\n    undef_method :concat\n    undef_method :<<\n  end\n\n  ##\n  # The \"sync mode\" of the SSLSocket.\n  #\n  # See IO#sync for full details.\n\n  attr_accessor :sync\n\n  ##\n  # Default size to read from or write to the SSLSocket for buffer operations.\n\n  BLOCK_SIZE = 1024*16\n\n  ##\n  # Creates an instance of OpenSSL's buffering IO module.\n\n  def initialize(*)\n    super\n    @eof = false\n    @rbuffer = Buffer.new\n    @sync = @io.sync\n  end\n\n  #\n  # for reading.\n  #\n  private\n\n  ##\n  # Fills the buffer from the underlying SSLSocket\n\n  def fill_rbuff\n    begin\n      @rbuffer.append_as_bytes(self.sysread(BLOCK_SIZE))\n    rescue Errno::EAGAIN\n      retry\n    rescue EOFError\n      @eof = true\n    end\n  end\n\n  ##\n  # Consumes _size_ bytes from the buffer\n\n  def consume_rbuff(size=nil)\n    if @rbuffer.empty?\n      nil\n    else\n      size = @rbuffer.size unless size\n      @rbuffer.slice!(0, size)\n    end\n  end\n\n  public\n\n  # call-seq:\n  #   ssl.getbyte => 81\n  #\n  # Get the next 8bit byte from `ssl`.  Returns `nil` on EOF\n  def getbyte\n    read(1)&.ord\n  end\n\n  # Get the next 8bit byte. Raises EOFError on EOF\n  def readbyte\n    raise EOFError if eof?\n    getbyte\n  end\n\n  ##\n  # Reads _size_ bytes from the stream.  If _buf_ is provided it must\n  # reference a string which will receive the data.\n  #\n  # See IO#read for full details.\n\n  def read(size=nil, buf=nil)\n    if size == 0\n      if buf\n        buf.clear\n        return buf\n      else\n        return \"\"\n      end\n    end\n    until @eof\n      break if size && size <= @rbuffer.size\n      fill_rbuff\n    end\n    ret = consume_rbuff(size) || \"\"\n    if buf\n      buf.replace(ret)\n      ret = buf\n    end\n    (size && ret.empty?) ? nil : ret\n  end\n\n  ##\n  # Reads at most _maxlen_ bytes from the stream.  If _buf_ is provided it\n  # must reference a string which will receive the data.\n  #\n  # See IO#readpartial for full details.\n\n  def readpartial(maxlen, buf=nil)\n    if maxlen == 0\n      if buf\n        buf.clear\n        return buf\n      else\n        return \"\"\n      end\n    end\n    if @rbuffer.empty?\n      begin\n        return sysread(maxlen, buf)\n      rescue Errno::EAGAIN\n        retry\n      end\n    end\n    ret = consume_rbuff(maxlen)\n    if buf\n      buf.replace(ret)\n      ret = buf\n    end\n    ret\n  end\n\n  ##\n  # Reads at most _maxlen_ bytes in the non-blocking manner.\n  #\n  # When no data can be read without blocking it raises\n  # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.\n  #\n  # IO::WaitReadable means SSL needs to read internally so read_nonblock\n  # should be called again when the underlying IO is readable.\n  #\n  # IO::WaitWritable means SSL needs to write internally so read_nonblock\n  # should be called again after the underlying IO is writable.\n  #\n  # OpenSSL::Buffering#read_nonblock needs two rescue clause as follows:\n  #\n  #   # emulates blocking read (readpartial).\n  #   begin\n  #     result = ssl.read_nonblock(maxlen)\n  #   rescue IO::WaitReadable\n  #     IO.select([io])\n  #     retry\n  #   rescue IO::WaitWritable\n  #     IO.select(nil, [io])\n  #     retry\n  #   end\n  #\n  # Note that one reason that read_nonblock writes to the underlying IO is\n  # when the peer requests a new TLS/SSL handshake.  See openssl the FAQ for\n  # more details.  http://www.openssl.org/support/faq.html\n  #\n  # By specifying a keyword argument _exception_ to +false+, you can indicate\n  # that read_nonblock should not raise an IO::Wait*able exception, but\n  # return the symbol +:wait_writable+ or +:wait_readable+ instead. At EOF,\n  # it will return +nil+ instead of raising EOFError.\n\n  def read_nonblock(maxlen, buf=nil, exception: true)\n    if maxlen == 0\n      if buf\n        buf.clear\n        return buf\n      else\n        return \"\"\n      end\n    end\n    if @rbuffer.empty?\n      return sysread_nonblock(maxlen, buf, exception: exception)\n    end\n    ret = consume_rbuff(maxlen)\n    if buf\n      buf.replace(ret)\n      ret = buf\n    end\n    ret\n  end\n\n  ##\n  # Reads the next \"line\" from the stream.  Lines are separated by _eol_.  If\n  # _limit_ is provided the result will not be longer than the given number of\n  # bytes.\n  #\n  # _eol_ may be a String or Regexp.\n  #\n  # Unlike IO#gets the line read will not be assigned to +$_+.\n  #\n  # Unlike IO#gets the separator must be provided if a limit is provided.\n\n  def gets(eol=$/, limit=nil, chomp: false)\n    idx = @rbuffer.index(eol)\n    until @eof\n      break if idx\n      fill_rbuff\n      idx = @rbuffer.index(eol)\n    end\n    if eol.is_a?(Regexp)\n      size = idx ? idx+$&.size : nil\n    else\n      size = idx ? idx+eol.size : nil\n    end\n    if size && limit && limit >= 0\n      size = [size, limit].min\n    end\n    line = consume_rbuff(size)\n    if chomp && line\n      line.chomp!(eol)\n    end\n    line\n  end\n\n  ##\n  # Executes the block for every line in the stream where lines are separated\n  # by _eol_.\n  #\n  # See also #gets\n\n  def each(eol=$/)\n    while line = self.gets(eol)\n      yield line\n    end\n  end\n  alias each_line each\n\n  ##\n  # Reads lines from the stream which are separated by _eol_.\n  #\n  # See also #gets\n\n  def readlines(eol=$/)\n    ary = []\n    while line = self.gets(eol)\n      ary << line\n    end\n    ary\n  end\n\n  ##\n  # Reads a line from the stream which is separated by _eol_.\n  #\n  # Raises EOFError if at end of file.\n\n  def readline(eol=$/)\n    raise EOFError if eof?\n    gets(eol)\n  end\n\n  ##\n  # Reads one character from the stream.  Returns nil if called at end of\n  # file.\n\n  def getc\n    read(1)\n  end\n\n  ##\n  # Calls the given block once for each byte in the stream.\n\n  def each_byte # :yields: byte\n    while c = getc\n      yield(c.ord)\n    end\n  end\n\n  ##\n  # Reads a one-character string from the stream.  Raises an EOFError at end\n  # of file.\n\n  def readchar\n    raise EOFError if eof?\n    getc\n  end\n\n  ##\n  # Pushes character _c_ back onto the stream such that a subsequent buffered\n  # character read will return it.\n  #\n  # Unlike IO#getc multiple bytes may be pushed back onto the stream.\n  #\n  # Has no effect on unbuffered reads (such as #sysread).\n\n  def ungetc(c)\n    @rbuffer[0,0] = c.chr\n  end\n\n  ##\n  # Returns true if the stream is at file which means there is no more data to\n  # be read.\n\n  def eof?\n    fill_rbuff if !@eof && @rbuffer.empty?\n    @eof && @rbuffer.empty?\n  end\n  alias eof eof?\n\n  #\n  # for writing.\n  #\n  private\n\n  ##\n  # Writes _s_ to the buffer.  When the buffer is full or #sync is true the\n  # buffer is flushed to the underlying socket.\n\n  def do_write(s)\n    @wbuffer = Buffer.new unless defined? @wbuffer\n    @wbuffer.append_as_bytes(s)\n\n    @sync ||= false\n    buffer_size = @wbuffer.bytesize\n    if @sync or buffer_size > BLOCK_SIZE\n      nwrote = 0\n      begin\n        while nwrote < buffer_size do\n          begin\n            chunk = if nwrote > 0\n              @wbuffer.byteslice(nwrote, @wbuffer.bytesize)\n            else\n              @wbuffer\n            end\n\n            nwrote += syswrite(chunk)\n          rescue Errno::EAGAIN\n            retry\n          end\n        end\n      ensure\n        if nwrote < @wbuffer.bytesize\n          @wbuffer[0, nwrote] = \"\"\n        else\n          @wbuffer.clear\n        end\n      end\n    end\n  end\n\n  public\n\n  ##\n  # Writes _s_ to the stream.  If the argument is not a String it will be\n  # converted using +.to_s+ method.  Returns the number of bytes written.\n\n  def write(*s)\n    s.inject(0) do |written, str|\n      do_write(str)\n      written + str.bytesize\n    end\n  end\n\n  ##\n  # Writes _s_ in the non-blocking manner.\n  #\n  # If there is buffered data, it is flushed first.  This may block.\n  #\n  # write_nonblock returns number of bytes written to the SSL connection.\n  #\n  # When no data can be written without blocking it raises\n  # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.\n  #\n  # IO::WaitReadable means SSL needs to read internally so write_nonblock\n  # should be called again after the underlying IO is readable.\n  #\n  # IO::WaitWritable means SSL needs to write internally so write_nonblock\n  # should be called again after underlying IO is writable.\n  #\n  # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows.\n  #\n  #   # emulates blocking write.\n  #   begin\n  #     result = ssl.write_nonblock(str)\n  #   rescue IO::WaitReadable\n  #     IO.select([io])\n  #     retry\n  #   rescue IO::WaitWritable\n  #     IO.select(nil, [io])\n  #     retry\n  #   end\n  #\n  # Note that one reason that write_nonblock reads from the underlying IO\n  # is when the peer requests a new TLS/SSL handshake.  See the openssl FAQ\n  # for more details.  http://www.openssl.org/support/faq.html\n  #\n  # By specifying a keyword argument _exception_ to +false+, you can indicate\n  # that write_nonblock should not raise an IO::Wait*able exception, but\n  # return the symbol +:wait_writable+ or +:wait_readable+ instead.\n\n  def write_nonblock(s, exception: true)\n    flush\n    syswrite_nonblock(s, exception: exception)\n  end\n\n  ##\n  # Writes _s_ to the stream.  _s_ will be converted to a String using\n  # +.to_s+ method.\n\n  def <<(s)\n    do_write(s)\n    self\n  end\n\n  ##\n  # Writes _args_ to the stream along with a record separator.\n  #\n  # See IO#puts for full details.\n\n  def puts(*args)\n    s = Buffer.new\n    if args.empty?\n      s.append_as_bytes(\"\\n\")\n    end\n    args.each{|arg|\n      s.append_as_bytes(arg.to_s)\n      s.sub!(/(?<!\\n)\\z/, \"\\n\")\n    }\n    do_write(s)\n    nil\n  end\n\n  ##\n  # Writes _args_ to the stream.\n  #\n  # See IO#print for full details.\n\n  def print(*args)\n    s = Buffer.new\n    args.each{ |arg| s.append_as_bytes(arg.to_s) }\n    do_write(s)\n    nil\n  end\n\n  ##\n  # Formats and writes to the stream converting parameters under control of\n  # the format string.\n  #\n  # See Kernel#sprintf for format string details.\n\n  def printf(s, *args)\n    do_write(s % args)\n    nil\n  end\n\n  ##\n  # Flushes buffered data to the SSLSocket.\n\n  def flush\n    osync = @sync\n    @sync = true\n    do_write \"\"\n    return self\n  ensure\n    @sync = osync\n  end\n\n  ##\n  # Closes the SSLSocket and flushes any unwritten data.\n\n  def close\n    flush rescue nil\n    sysclose\n  end\nend\n"
  },
  {
    "path": "lib/openssl/cipher.rb",
    "content": "# frozen_string_literal: true\n#--\n# = Ruby-space predefined Cipher subclasses\n#\n# = Info\n# 'OpenSSL for Ruby 2' project\n# Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>\n# All rights reserved.\n#\n# = Licence\n# This program is licensed under the same licence as Ruby.\n# (See the file 'COPYING'.)\n#++\n\nmodule OpenSSL\n  class Cipher\n    %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name|\n      klass = Class.new(Cipher){\n        define_method(:initialize){|*args|\n          cipher_name = args.inject(name){|n, arg| \"#{n}-#{arg}\" }\n          super(cipher_name.downcase)\n        }\n      }\n      const_set(name, klass)\n    }\n\n    %w(128 192 256).each{|keylen|\n      klass = Class.new(Cipher){\n        define_method(:initialize){|mode = \"CBC\"|\n          super(\"aes-#{keylen}-#{mode}\".downcase)\n        }\n      }\n      const_set(\"AES#{keylen}\", klass)\n    }\n\n    # call-seq:\n    #   cipher.random_key -> key\n    #\n    # Generate a random key with OpenSSL::Random.random_bytes and sets it to\n    # the cipher, and returns it.\n    #\n    # You must call #encrypt or #decrypt before calling this method.\n    def random_key\n      str = OpenSSL::Random.random_bytes(self.key_len)\n      self.key = str\n    end\n\n    # call-seq:\n    #   cipher.random_iv -> iv\n    #\n    # Generate a random IV with OpenSSL::Random.random_bytes and sets it to the\n    # cipher, and returns it.\n    #\n    # You must call #encrypt or #decrypt before calling this method.\n    def random_iv\n      str = OpenSSL::Random.random_bytes(self.iv_len)\n      self.iv = str\n    end\n\n    # Deprecated.\n    #\n    # This class is only provided for backwards compatibility.\n    # Use OpenSSL::Cipher.\n    class Cipher < Cipher; end\n    deprecate_constant :Cipher\n  end # Cipher\nend # OpenSSL\n"
  },
  {
    "path": "lib/openssl/digest.rb",
    "content": "# frozen_string_literal: true\n#--\n# = Ruby-space predefined Digest subclasses\n#\n# = Info\n# 'OpenSSL for Ruby 2' project\n# Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>\n# All rights reserved.\n#\n# = Licence\n# This program is licensed under the same licence as Ruby.\n# (See the file 'COPYING'.)\n#++\n\nmodule OpenSSL\n  class Digest\n\n    # Return the hash value computed with _name_ Digest. _name_ is either the\n    # long name or short name of a supported digest algorithm.\n    #\n    # === Example\n    #\n    #   OpenSSL::Digest.digest(\"SHA256\", \"abc\")\n\n    def self.digest(name, data)\n      super(data, name)\n    end\n\n    %w(MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512).each do |name|\n      klass = Class.new(self) {\n        define_method(:initialize, ->(data = nil) {super(name, data)})\n      }\n\n      singleton = (class << klass; self; end)\n\n      singleton.class_eval{\n        define_method(:digest) {|data| new.digest(data)}\n        define_method(:hexdigest) {|data| new.hexdigest(data)}\n      }\n\n      const_set(name.tr('-', '_'), klass)\n    end\n\n    # Deprecated.\n    #\n    # This class is only provided for backwards compatibility.\n    # Use OpenSSL::Digest instead.\n    class Digest < Digest; end # :nodoc:\n    deprecate_constant :Digest\n\n  end # Digest\n\n  # Returns a Digest subclass by _name_\n  #\n  #   require 'openssl'\n  #\n  #   OpenSSL::Digest(\"MD5\")\n  #   # => OpenSSL::Digest::MD5\n  #\n  #   OpenSSL::Digest(\"Foo\")\n  #   # => NameError: wrong constant name Foo\n\n  def Digest(name)\n    OpenSSL::Digest.const_get(name)\n  end\n\n  module_function :Digest\n\nend # OpenSSL\n"
  },
  {
    "path": "lib/openssl/hmac.rb",
    "content": "# frozen_string_literal: true\n\nmodule OpenSSL\n  class HMAC\n    # Securely compare with another HMAC instance in constant time.\n    def ==(other)\n      return false unless HMAC === other\n      return false unless self.digest.bytesize == other.digest.bytesize\n\n      OpenSSL.fixed_length_secure_compare(self.digest, other.digest)\n    end\n\n    # :call-seq:\n    #    hmac.base64digest -> string\n    #\n    # Returns the authentication code an a Base64-encoded string.\n    def base64digest\n      [digest].pack(\"m0\")\n    end\n\n    class << self\n      # :call-seq:\n      #    HMAC.digest(digest, key, data) -> aString\n      #\n      # Returns the authentication code as a binary string. The _digest_ parameter\n      # specifies the digest algorithm to use. This may be a String representing\n      # the algorithm name or an instance of OpenSSL::Digest.\n      #\n      # === Example\n      #  key = 'key'\n      #  data = 'The quick brown fox jumps over the lazy dog'\n      #\n      #  hmac = OpenSSL::HMAC.digest('SHA1', key, data)\n      #  #=> \"\\xDE|\\x9B\\x85\\xB8\\xB7\\x8A\\xA6\\xBC\\x8Az6\\xF7\\n\\x90p\\x1C\\x9D\\xB4\\xD9\"\n      def digest(digest, key, data)\n        hmac = new(key, digest)\n        hmac << data\n        hmac.digest\n      end\n\n      # :call-seq:\n      #    HMAC.hexdigest(digest, key, data) -> aString\n      #\n      # Returns the authentication code as a hex-encoded string. The _digest_\n      # parameter specifies the digest algorithm to use. This may be a String\n      # representing the algorithm name or an instance of OpenSSL::Digest.\n      #\n      # === Example\n      #  key = 'key'\n      #  data = 'The quick brown fox jumps over the lazy dog'\n      #\n      #  hmac = OpenSSL::HMAC.hexdigest('SHA1', key, data)\n      #  #=> \"de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9\"\n      def hexdigest(digest, key, data)\n        hmac = new(key, digest)\n        hmac << data\n        hmac.hexdigest\n      end\n\n      # :call-seq:\n      #    HMAC.base64digest(digest, key, data) -> aString\n      #\n      # Returns the authentication code as a Base64-encoded string. The _digest_\n      # parameter specifies the digest algorithm to use. This may be a String\n      # representing the algorithm name or an instance of OpenSSL::Digest.\n      #\n      # === Example\n      #  key = 'key'\n      #  data = 'The quick brown fox jumps over the lazy dog'\n      #\n      #  hmac = OpenSSL::HMAC.base64digest('SHA1', key, data)\n      #  #=> \"3nybhbi3iqa8ino29wqQcBydtNk=\"\n      def base64digest(digest, key, data)\n        [digest(digest, key, data)].pack(\"m0\")\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/openssl/marshal.rb",
    "content": "# frozen_string_literal: true\n#--\n# = Ruby-space definitions to add DER (de)serialization to classes\n#\n# = Info\n# 'OpenSSL for Ruby 2' project\n# Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>\n# All rights reserved.\n#\n# = Licence\n# This program is licensed under the same licence as Ruby.\n# (See the file 'COPYING'.)\n#++\nmodule OpenSSL\n  module Marshal\n    def self.included(base)\n      base.extend(ClassMethods)\n    end\n\n    module ClassMethods\n      def _load(string)\n        new(string)\n      end\n    end\n\n    def _dump(_level)\n      to_der\n    end\n  end\nend\n"
  },
  {
    "path": "lib/openssl/pkcs5.rb",
    "content": "# frozen_string_literal: true\n#--\n# Ruby/OpenSSL Project\n# Copyright (C) 2017 Ruby/OpenSSL Project Authors\n#++\n\nmodule OpenSSL\n  module PKCS5\n    module_function\n\n    # OpenSSL::PKCS5.pbkdf2_hmac has been renamed to OpenSSL::KDF.pbkdf2_hmac.\n    # This method is provided for backwards compatibility.\n    def pbkdf2_hmac(pass, salt, iter, keylen, digest)\n      OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter,\n                               length: keylen, hash: digest)\n    end\n\n    def pbkdf2_hmac_sha1(pass, salt, iter, keylen)\n      pbkdf2_hmac(pass, salt, iter, keylen, \"sha1\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/openssl/pkey.rb",
    "content": "# frozen_string_literal: true\n#--\n# Ruby/OpenSSL Project\n# Copyright (C) 2017 Ruby/OpenSSL Project Authors\n#++\n\nrequire_relative 'marshal'\n\nmodule OpenSSL::PKey\n  # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.\n  DHError = PKeyError\n\n  class DH\n    include OpenSSL::Marshal\n\n    # :call-seq:\n    #    dh.public_key -> dhnew\n    #\n    # Returns a new DH instance that carries just the \\DH parameters.\n    #\n    # Contrary to the method name, the returned DH object contains only\n    # parameters and not the public key.\n    #\n    # This method is provided for backwards compatibility. In most cases, there\n    # is no need to call this method.\n    #\n    # For the purpose of re-generating the key pair while keeping the\n    # parameters, check OpenSSL::PKey.generate_key.\n    #\n    # Example:\n    #   # OpenSSL::PKey::DH.generate by default generates a random key pair\n    #   dh1 = OpenSSL::PKey::DH.generate(2048)\n    #   p dh1.priv_key #=> #<OpenSSL::BN 1288347...>\n    #   dhcopy = dh1.public_key\n    #   p dhcopy.priv_key #=> nil\n    def public_key\n      DH.new(to_der)\n    end\n\n    # :call-seq:\n    #    dh.params -> hash\n    #\n    # Stores all parameters of key to a Hash.\n    #\n    # The hash has keys 'p', 'q', 'g', 'pub_key', and 'priv_key'.\n    def params\n      %w{p q g pub_key priv_key}.map { |name|\n        [name, send(name)]\n      }.to_h\n    end\n\n    # :call-seq:\n    #    dh.compute_key(pub_bn) -> string\n    #\n    # Returns a String containing a shared secret computed from the other\n    # party's public value.\n    #\n    # This method is provided for backwards compatibility, and calls #derive\n    # internally.\n    #\n    # === Parameters\n    # * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by\n    #   DH#public_key as that contains the DH parameters only.\n    def compute_key(pub_bn)\n      # FIXME: This is constructing an X.509 SubjectPublicKeyInfo and is very\n      # inefficient\n      obj = OpenSSL::ASN1.Sequence([\n        OpenSSL::ASN1.Sequence([\n          OpenSSL::ASN1.ObjectId(\"dhKeyAgreement\"),\n          OpenSSL::ASN1.Sequence([\n            OpenSSL::ASN1.Integer(p),\n            OpenSSL::ASN1.Integer(g),\n          ]),\n        ]),\n        OpenSSL::ASN1.BitString(OpenSSL::ASN1.Integer(pub_bn).to_der),\n      ])\n      derive(OpenSSL::PKey.read(obj.to_der))\n    end\n\n    # :call-seq:\n    #    dh.generate_key! -> self\n    #\n    # Generates a private and public key unless a private key already exists.\n    # If this DH instance was generated from public \\DH parameters (e.g. by\n    # encoding the result of DH#public_key), then this method needs to be\n    # called first in order to generate the per-session keys before performing\n    # the actual key exchange.\n    #\n    # <b>Deprecated in version 3.0</b>. This method is incompatible with\n    # OpenSSL 3.0.0 or later.\n    #\n    # See also OpenSSL::PKey.generate_key.\n    #\n    # Example:\n    #   # DEPRECATED USAGE: This will not work on OpenSSL 3.0 or later\n    #   dh0 = OpenSSL::PKey::DH.new(2048)\n    #   dh = dh0.public_key # #public_key only copies the DH parameters (contrary to the name)\n    #   dh.generate_key!\n    #   puts dh.private? # => true\n    #   puts dh0.pub_key == dh.pub_key #=> false\n    #\n    #   # With OpenSSL::PKey.generate_key\n    #   dh0 = OpenSSL::PKey::DH.new(2048)\n    #   dh = OpenSSL::PKey.generate_key(dh0)\n    #   puts dh0.pub_key == dh.pub_key #=> false\n    def generate_key!\n      if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000\n        raise PKeyError, \"OpenSSL::PKey::DH is immutable on OpenSSL 3.0; \" \\\n        \"use OpenSSL::PKey.generate_key instead\"\n      end\n\n      unless priv_key\n        tmp = OpenSSL::PKey.generate_key(self)\n        set_key(tmp.pub_key, tmp.priv_key)\n      end\n      self\n    end\n\n    class << self\n      # :call-seq:\n      #    DH.generate(size, generator = 2) -> dh\n      #\n      # Creates a new DH instance from scratch by generating random parameters\n      # and a key pair.\n      #\n      # See also OpenSSL::PKey.generate_parameters and\n      # OpenSSL::PKey.generate_key.\n      #\n      # +size+::\n      #   The desired key size in bits.\n      # +generator+::\n      #   The generator.\n      def generate(size, generator = 2, &blk)\n        dhparams = OpenSSL::PKey.generate_parameters(\"DH\", {\n          \"dh_paramgen_prime_len\" => size,\n          \"dh_paramgen_generator\" => generator,\n        }, &blk)\n        OpenSSL::PKey.generate_key(dhparams)\n      end\n\n      # Handle DH.new(size, generator) form here; new(str) and new() forms\n      # are handled by #initialize\n      def new(*args, &blk) # :nodoc:\n        if args[0].is_a?(Integer)\n          generate(*args, &blk)\n        else\n          super\n        end\n      end\n    end\n  end\n\n  # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.\n  DSAError = PKeyError\n\n  class DSA\n    include OpenSSL::Marshal\n\n    # :call-seq:\n    #    dsa.public_key -> dsanew\n    #\n    # Returns a new DSA instance that carries just the \\DSA parameters and the\n    # public key.\n    #\n    # This method is provided for backwards compatibility. In most cases, there\n    # is no need to call this method.\n    #\n    # For the purpose of serializing the public key, to PEM or DER encoding of\n    # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and\n    # PKey#public_to_der.\n    def public_key\n      OpenSSL::PKey.read(public_to_der)\n    end\n\n    # :call-seq:\n    #    dsa.params -> hash\n    #\n    # Stores all parameters of key to a Hash.\n    #\n    # The hash has keys 'p', 'q', 'g', 'pub_key', and 'priv_key'.\n    def params\n      %w{p q g pub_key priv_key}.map { |name|\n        [name, send(name)]\n      }.to_h\n    end\n\n    class << self\n      # :call-seq:\n      #    DSA.generate(size) -> dsa\n      #\n      # Creates a new DSA instance by generating a private/public key pair\n      # from scratch.\n      #\n      # See also OpenSSL::PKey.generate_parameters and\n      # OpenSSL::PKey.generate_key.\n      #\n      # +size+::\n      #   The desired key size in bits.\n      def generate(size, &blk)\n        # FIPS 186-4 specifies four (L,N) pairs: (1024,160), (2048,224),\n        # (2048,256), and (3072,256).\n        #\n        # q size is derived here with compatibility with\n        # DSA_generator_parameters_ex() which previous versions of ruby/openssl\n        # used to call.\n        qsize = size >= 2048 ? 256 : 160\n        dsaparams = OpenSSL::PKey.generate_parameters(\"DSA\", {\n          \"dsa_paramgen_bits\" => size,\n          \"dsa_paramgen_q_bits\" => qsize,\n        }, &blk)\n        OpenSSL::PKey.generate_key(dsaparams)\n      end\n\n      # Handle DSA.new(size) form here; new(str) and new() forms\n      # are handled by #initialize\n      def new(*args, &blk) # :nodoc:\n        if args[0].is_a?(Integer)\n          generate(*args, &blk)\n        else\n          super\n        end\n      end\n    end\n\n    # :call-seq:\n    #    dsa.syssign(string) -> string\n    #\n    # Computes and returns the \\DSA signature of +string+, where +string+ is\n    # expected to be an already-computed message digest of the original input\n    # data. The signature is issued using the private key of this DSA instance.\n    #\n    # <b>Deprecated in version 3.0</b>.\n    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.\n    #\n    # +string+::\n    #   A message digest of the original input data to be signed.\n    #\n    # Example:\n    #   dsa = OpenSSL::PKey::DSA.new(2048)\n    #   doc = \"Sign me\"\n    #   digest = OpenSSL::Digest.digest('SHA1', doc)\n    #\n    #   # With legacy #syssign and #sysverify:\n    #   sig = dsa.syssign(digest)\n    #   p dsa.sysverify(digest, sig) #=> true\n    #\n    #   # With #sign_raw and #verify_raw:\n    #   sig = dsa.sign_raw(nil, digest)\n    #   p dsa.verify_raw(nil, sig, digest) #=> true\n    def syssign(string)\n      q or raise PKeyError, \"incomplete DSA\"\n      private? or raise PKeyError, \"Private DSA key needed!\"\n      sign_raw(nil, string)\n    end\n\n    # :call-seq:\n    #    dsa.sysverify(digest, sig) -> true | false\n    #\n    # Verifies whether the signature is valid given the message digest input.\n    # It does so by validating +sig+ using the public key of this DSA instance.\n    #\n    # <b>Deprecated in version 3.0</b>.\n    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.\n    #\n    # +digest+::\n    #   A message digest of the original input data to be signed.\n    # +sig+::\n    #   A \\DSA signature value.\n    def sysverify(digest, sig)\n      verify_raw(nil, sig, digest)\n    end\n  end\n\n  if defined?(EC)\n  # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.\n  ECError = PKeyError\n\n  class EC\n    include OpenSSL::Marshal\n\n    # :call-seq:\n    #    key.dsa_sign_asn1(data) -> String\n    #\n    # <b>Deprecated in version 3.0</b>.\n    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.\n    def dsa_sign_asn1(data)\n      sign_raw(nil, data)\n    end\n\n    # :call-seq:\n    #    key.dsa_verify_asn1(data, sig) -> true | false\n    #\n    # <b>Deprecated in version 3.0</b>.\n    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.\n    def dsa_verify_asn1(data, sig)\n      verify_raw(nil, sig, data)\n    end\n\n    # :call-seq:\n    #    ec.dh_compute_key(pubkey) -> string\n    #\n    # Derives a shared secret by ECDH. _pubkey_ must be an instance of\n    # OpenSSL::PKey::EC::Point and must belong to the same group.\n    #\n    # This method is provided for backwards compatibility, and calls #derive\n    # internally.\n    def dh_compute_key(pubkey)\n      obj = OpenSSL::ASN1.Sequence([\n        OpenSSL::ASN1.Sequence([\n          OpenSSL::ASN1.ObjectId(\"id-ecPublicKey\"),\n          group.to_der,\n        ]),\n        OpenSSL::ASN1.BitString(pubkey.to_octet_string(:uncompressed)),\n      ])\n      derive(OpenSSL::PKey.read(obj.to_der))\n    end\n  end\n\n  class EC::Point\n    # :call-seq:\n    #    point.to_bn([conversion_form]) -> OpenSSL::BN\n    #\n    # Returns the octet string representation of the EC point as an instance of\n    # OpenSSL::BN.\n    #\n    # If _conversion_form_ is not given, the _point_conversion_form_ attribute\n    # set to the group is used.\n    #\n    # See #to_octet_string for more information.\n    def to_bn(conversion_form = group.point_conversion_form)\n      OpenSSL::BN.new(to_octet_string(conversion_form), 2)\n    end\n  end\n  end\n\n  # Alias of PKeyError. Before version 4.0.0, this was a subclass of PKeyError.\n  RSAError = PKeyError\n\n  class RSA\n    include OpenSSL::Marshal\n\n    # :call-seq:\n    #    rsa.public_key -> rsanew\n    #\n    # Returns a new RSA instance that carries just the public key components.\n    #\n    # This method is provided for backwards compatibility. In most cases, there\n    # is no need to call this method.\n    #\n    # For the purpose of serializing the public key, to PEM or DER encoding of\n    # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and\n    # PKey#public_to_der.\n    def public_key\n      OpenSSL::PKey.read(public_to_der)\n    end\n\n    # :call-seq:\n    #    rsa.params -> hash\n    #\n    # Stores all parameters of key to a Hash.\n    #\n    # The hash has keys 'n', 'e', 'd', 'p', 'q', 'dmp1', 'dmq1', and 'iqmp'.\n    def params\n      %w{n e d p q dmp1 dmq1 iqmp}.map { |name|\n        [name, send(name)]\n      }.to_h\n    end\n\n    class << self\n      # :call-seq:\n      #    RSA.generate(size, exponent = 65537) -> RSA\n      #\n      # Generates an \\RSA keypair.\n      #\n      # See also OpenSSL::PKey.generate_key.\n      #\n      # +size+::\n      #   The desired key size in bits.\n      # +exponent+::\n      #   An odd Integer, normally 3, 17, or 65537.\n      def generate(size, exp = 0x10001, &blk)\n        OpenSSL::PKey.generate_key(\"RSA\", {\n          \"rsa_keygen_bits\" => size,\n          \"rsa_keygen_pubexp\" => exp,\n        }, &blk)\n      end\n\n      # Handle RSA.new(size, exponent) form here; new(str) and new() forms\n      # are handled by #initialize\n      def new(*args, &blk) # :nodoc:\n        if args[0].is_a?(Integer)\n          generate(*args, &blk)\n        else\n          super\n        end\n      end\n    end\n\n    # :call-seq:\n    #    rsa.private_encrypt(string)          -> String\n    #    rsa.private_encrypt(string, padding) -> String\n    #\n    # Encrypt +string+ with the private key.  +padding+ defaults to\n    # PKCS1_PADDING, which is known to be insecure but is kept for backwards\n    # compatibility. The encrypted string output can be decrypted using\n    # #public_decrypt.\n    #\n    # <b>Deprecated in version 3.0</b>.\n    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and\n    # PKey::PKey#verify_recover instead.\n    def private_encrypt(string, padding = PKCS1_PADDING)\n      n or raise PKeyError, \"incomplete RSA\"\n      private? or raise PKeyError, \"private key needed.\"\n      sign_raw(nil, string, {\n        \"rsa_padding_mode\" => translate_padding_mode(padding),\n      })\n    end\n\n    # :call-seq:\n    #    rsa.public_decrypt(string)          -> String\n    #    rsa.public_decrypt(string, padding) -> String\n    #\n    # Decrypt +string+, which has been encrypted with the private key, with the\n    # public key.  +padding+ defaults to PKCS1_PADDING which is known to be\n    # insecure but is kept for backwards compatibility.\n    #\n    # <b>Deprecated in version 3.0</b>.\n    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and\n    # PKey::PKey#verify_recover instead.\n    def public_decrypt(string, padding = PKCS1_PADDING)\n      n or raise PKeyError, \"incomplete RSA\"\n      verify_recover(nil, string, {\n        \"rsa_padding_mode\" => translate_padding_mode(padding),\n      })\n    end\n\n    # :call-seq:\n    #    rsa.public_encrypt(string)          -> String\n    #    rsa.public_encrypt(string, padding) -> String\n    #\n    # Encrypt +string+ with the public key.  +padding+ defaults to\n    # PKCS1_PADDING, which is known to be insecure but is kept for backwards\n    # compatibility. The encrypted string output can be decrypted using\n    # #private_decrypt.\n    #\n    # <b>Deprecated in version 3.0</b>.\n    # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.\n    def public_encrypt(data, padding = PKCS1_PADDING)\n      n or raise PKeyError, \"incomplete RSA\"\n      encrypt(data, {\n        \"rsa_padding_mode\" => translate_padding_mode(padding),\n      })\n    end\n\n    # :call-seq:\n    #    rsa.private_decrypt(string)          -> String\n    #    rsa.private_decrypt(string, padding) -> String\n    #\n    # Decrypt +string+, which has been encrypted with the public key, with the\n    # private key. +padding+ defaults to PKCS1_PADDING, which is known to be\n    # insecure but is kept for backwards compatibility.\n    #\n    # <b>Deprecated in version 3.0</b>.\n    # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.\n    def private_decrypt(data, padding = PKCS1_PADDING)\n      n or raise PKeyError, \"incomplete RSA\"\n      private? or raise PKeyError, \"private key needed.\"\n      decrypt(data, {\n        \"rsa_padding_mode\" => translate_padding_mode(padding),\n      })\n    end\n\n    PKCS1_PADDING = 1\n    SSLV23_PADDING = 2\n    NO_PADDING = 3\n    PKCS1_OAEP_PADDING = 4\n\n    private def translate_padding_mode(num)\n      case num\n      when PKCS1_PADDING\n        \"pkcs1\"\n      when SSLV23_PADDING\n        \"sslv23\"\n      when NO_PADDING\n        \"none\"\n      when PKCS1_OAEP_PADDING\n        \"oaep\"\n      else\n        raise PKeyError, \"unsupported padding mode\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/openssl/ssl.rb",
    "content": "# frozen_string_literal: true\n=begin\n= Info\n  'OpenSSL for Ruby 2' project\n  Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>\n  All rights reserved.\n\n= Licence\n  This program is licensed under the same licence as Ruby.\n  (See the file 'COPYING'.)\n=end\n\nrequire \"openssl/buffering\"\n\nif defined?(OpenSSL::SSL)\n\nrequire \"io/nonblock\"\nrequire \"ipaddr\"\nrequire \"socket\"\n\nmodule OpenSSL\n  module SSL\n    class SSLContext\n      DEFAULT_PARAMS = { # :nodoc:\n        :verify_mode => OpenSSL::SSL::VERIFY_PEER,\n        :verify_hostname => true,\n        :options => -> {\n          opts = OpenSSL::SSL::OP_ALL\n          opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS\n          opts |= OpenSSL::SSL::OP_NO_COMPRESSION\n          opts\n        }.call\n      }\n\n      if !OpenSSL::OPENSSL_VERSION.start_with?(\"OpenSSL\")\n        DEFAULT_PARAMS.merge!(\n          min_version: OpenSSL::SSL::TLS1_VERSION,\n          ciphers: %w{\n            ECDHE-ECDSA-AES128-GCM-SHA256\n            ECDHE-RSA-AES128-GCM-SHA256\n            ECDHE-ECDSA-AES256-GCM-SHA384\n            ECDHE-RSA-AES256-GCM-SHA384\n            DHE-RSA-AES128-GCM-SHA256\n            DHE-DSS-AES128-GCM-SHA256\n            DHE-RSA-AES256-GCM-SHA384\n            DHE-DSS-AES256-GCM-SHA384\n            ECDHE-ECDSA-AES128-SHA256\n            ECDHE-RSA-AES128-SHA256\n            ECDHE-ECDSA-AES128-SHA\n            ECDHE-RSA-AES128-SHA\n            ECDHE-ECDSA-AES256-SHA384\n            ECDHE-RSA-AES256-SHA384\n            ECDHE-ECDSA-AES256-SHA\n            ECDHE-RSA-AES256-SHA\n            DHE-RSA-AES128-SHA256\n            DHE-RSA-AES256-SHA256\n            DHE-RSA-AES128-SHA\n            DHE-RSA-AES256-SHA\n            DHE-DSS-AES128-SHA256\n            DHE-DSS-AES256-SHA256\n            DHE-DSS-AES128-SHA\n            DHE-DSS-AES256-SHA\n            AES128-GCM-SHA256\n            AES256-GCM-SHA384\n            AES128-SHA256\n            AES256-SHA256\n            AES128-SHA\n            AES256-SHA\n          }.join(\":\").freeze,\n        )\n      end\n      DEFAULT_PARAMS.freeze\n\n      DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc:\n      DEFAULT_CERT_STORE.set_default_paths\n\n      # A callback invoked at connect time to distinguish between multiple\n      # server names.\n      #\n      # The callback is invoked with an SSLSocket and a server name.  The\n      # callback must return an SSLContext for the server name or nil.\n      attr_accessor :servername_cb\n\n      # call-seq:\n      #    SSLContext.new           -> ctx\n      #    SSLContext.new(:TLSv1)   -> ctx\n      #    SSLContext.new(\"SSLv23\") -> ctx\n      #\n      # Creates a new SSL context.\n      #\n      # If an argument is given, #ssl_version= is called with the value. Note\n      # that this form is deprecated. New applications should use #min_version=\n      # and #max_version= as necessary.\n      def initialize(version = nil)\n        self.ssl_version = version if version\n        self.verify_mode = OpenSSL::SSL::VERIFY_NONE\n        self.verify_hostname = false\n      end\n\n      ##\n      # call-seq:\n      #   ctx.set_params(params = {}) -> params\n      #\n      # Sets saner defaults optimized for the use with HTTP-like protocols.\n      #\n      # If a Hash _params_ is given, the parameters are overridden with it.\n      # The keys in _params_ must be assignment methods on SSLContext.\n      #\n      # If the verify_mode is not VERIFY_NONE and ca_file, ca_path and\n      # cert_store are not set then the system default certificate store is\n      # used.\n      def set_params(params={})\n        params = DEFAULT_PARAMS.merge(params)\n        self.options |= params.delete(:options) # set before min_version/max_version\n        params.each{|name, value| self.__send__(\"#{name}=\", value) }\n        if self.verify_mode != OpenSSL::SSL::VERIFY_NONE\n          unless self.ca_file or self.ca_path or self.cert_store\n            if not defined?(Ractor) or Ractor.current == Ractor.main\n              self.cert_store = DEFAULT_CERT_STORE\n            else\n              self.cert_store = Ractor.current[:__openssl_default_store__] ||=\n                OpenSSL::X509::Store.new.tap { |store|\n                  store.set_default_paths\n                }\n            end\n          end\n        end\n        return params\n      end\n\n      # call-seq:\n      #    ctx.ssl_version = :TLSv1\n      #    ctx.ssl_version = \"SSLv23\"\n      #\n      # Sets the SSL/TLS protocol version for the context. This forces\n      # connections to use only the specified protocol version. This is\n      # deprecated and only provided for backwards compatibility. Use\n      # #min_version= and #max_version= instead.\n      #\n      # === History\n      # As the name hints, this used to call the SSL_CTX_set_ssl_version()\n      # function which sets the SSL method used for connections created from\n      # the context. As of Ruby/OpenSSL 2.1, this accessor method is\n      # implemented to call #min_version= and #max_version= instead.\n      def ssl_version=(meth)\n        meth = meth.to_s if meth.is_a?(Symbol)\n        if /(?<type>_client|_server)\\z/ =~ meth\n          meth = $`\n          if $VERBOSE\n            warn \"#{caller(1, 1)[0]}: method type #{type.inspect} is ignored\"\n          end\n        end\n        version = METHODS_MAP[meth.intern] or\n          raise ArgumentError, \"unknown SSL method `%s'\" % meth\n        self.min_version = self.max_version = version\n      end\n\n      METHODS_MAP = {\n        SSLv23: 0,\n        SSLv2: OpenSSL::SSL::SSL2_VERSION,\n        SSLv3: OpenSSL::SSL::SSL3_VERSION,\n        TLSv1: OpenSSL::SSL::TLS1_VERSION,\n        TLSv1_1: OpenSSL::SSL::TLS1_1_VERSION,\n        TLSv1_2: OpenSSL::SSL::TLS1_2_VERSION,\n      }.freeze\n      private_constant :METHODS_MAP\n\n      # The list of available SSL/TLS methods. This constant is only provided\n      # for backwards compatibility.\n      METHODS = METHODS_MAP.flat_map { |name,|\n        [name, :\"#{name}_client\", :\"#{name}_server\"]\n      }.freeze\n      deprecate_constant :METHODS\n    end\n\n    module SocketForwarder\n      # The file descriptor for the socket.\n      def fileno\n        to_io.fileno\n      end\n\n      def addr\n        to_io.addr\n      end\n\n      def peeraddr\n        to_io.peeraddr\n      end\n\n      def local_address\n        to_io.local_address\n      end\n\n      def remote_address\n        to_io.remote_address\n      end\n\n      def setsockopt(level, optname, optval)\n        to_io.setsockopt(level, optname, optval)\n      end\n\n      def getsockopt(level, optname)\n        to_io.getsockopt(level, optname)\n      end\n\n      def fcntl(*args)\n        to_io.fcntl(*args)\n      end\n\n      def closed?\n        to_io.closed?\n      end\n\n      def do_not_reverse_lookup=(flag)\n        to_io.do_not_reverse_lookup = flag\n      end\n\n      def close_on_exec=(value)\n        to_io.close_on_exec = value\n      end\n\n      def close_on_exec?\n        to_io.close_on_exec?\n      end\n\n      def wait(*args)\n        to_io.wait(*args)\n      end\n\n      def wait_readable(*args)\n        to_io.wait_readable(*args)\n      end\n\n      def wait_writable(*args)\n        to_io.wait_writable(*args)\n      end\n\n      if IO.method_defined?(:timeout)\n        def timeout\n          to_io.timeout\n        end\n\n        def timeout=(value)\n          to_io.timeout=(value)\n        end\n      end\n    end\n\n    def verify_certificate_identity(cert, hostname)\n      should_verify_common_name = true\n      cert.extensions.each{|ext|\n        next if ext.oid != \"subjectAltName\"\n        ostr = OpenSSL::ASN1.decode(ext.to_der).value.last\n        sequence = OpenSSL::ASN1.decode(ostr.value)\n        sequence.value.each{|san|\n          case san.tag\n          when 2 # dNSName in GeneralName (RFC5280)\n            should_verify_common_name = false\n            return true if verify_hostname(hostname, san.value)\n          when 7 # iPAddress in GeneralName (RFC5280)\n            should_verify_common_name = false\n            if san.value.size == 4 || san.value.size == 16\n              begin\n                return true if san.value == IPAddr.new(hostname).hton\n              rescue IPAddr::InvalidAddressError\n              end\n            end\n          end\n        }\n      }\n      if should_verify_common_name\n        cert.subject.to_a.each{|oid, value|\n          if oid == \"CN\"\n            return true if verify_hostname(hostname, value)\n          end\n        }\n      end\n      return false\n    end\n    module_function :verify_certificate_identity\n\n    def verify_hostname(hostname, san) # :nodoc:\n      # RFC 5280, IA5String is limited to the set of ASCII characters\n      return false unless san.ascii_only?\n      return false unless hostname.ascii_only?\n\n      # See RFC 6125, section 6.4.1\n      # Matching is case-insensitive.\n      san_parts = san.downcase.split(\".\")\n\n      # TODO: this behavior should probably be more strict\n      return san == hostname if san_parts.size < 2\n\n      # Matching is case-insensitive.\n      host_parts = hostname.downcase.split(\".\")\n\n      # RFC 6125, section 6.4.3, subitem 2.\n      # If the wildcard character is the only character of the left-most\n      # label in the presented identifier, the client SHOULD NOT compare\n      # against anything but the left-most label of the reference\n      # identifier (e.g., *.example.com would match foo.example.com but\n      # not bar.foo.example.com or example.com).\n      return false unless san_parts.size == host_parts.size\n\n      # RFC 6125, section 6.4.3, subitem 1.\n      # The client SHOULD NOT attempt to match a presented identifier in\n      # which the wildcard character comprises a label other than the\n      # left-most label (e.g., do not match bar.*.example.net).\n      return false unless verify_wildcard(host_parts.shift, san_parts.shift)\n\n      san_parts.join(\".\") == host_parts.join(\".\")\n    end\n    module_function :verify_hostname\n\n    def verify_wildcard(domain_component, san_component) # :nodoc:\n      parts = san_component.split(\"*\", -1)\n\n      return false if parts.size > 2\n      return san_component == domain_component if parts.size == 1\n\n      # RFC 6125, section 6.4.3, subitem 3.\n      # The client SHOULD NOT attempt to match a presented identifier\n      # where the wildcard character is embedded within an A-label or\n      # U-label of an internationalized domain name.\n      return false if domain_component.start_with?(\"xn--\") && san_component != \"*\"\n\n      parts[0].length + parts[1].length < domain_component.length &&\n      domain_component.start_with?(parts[0]) &&\n      domain_component.end_with?(parts[1])\n    end\n    module_function :verify_wildcard\n\n    class SSLSocket\n      include Buffering\n      include SocketForwarder\n\n      attr_reader :hostname\n\n      # The underlying IO object.\n      attr_reader :io\n      alias :to_io :io\n\n      # The SSLContext object used in this connection.\n      attr_reader :context\n\n      # Whether to close the underlying socket as well, when the SSL/TLS\n      # connection is shut down. This defaults to +false+.\n      attr_accessor :sync_close\n\n      # call-seq:\n      #    ssl.sysclose => nil\n      #\n      # Sends \"close notify\" to the peer and tries to shut down the SSL\n      # connection gracefully.\n      #\n      # If sync_close is set to +true+, the underlying IO is also closed.\n      def sysclose\n        return if closed?\n        stop\n        io.close if sync_close\n      end\n\n      # call-seq:\n      #   ssl.post_connection_check(hostname) -> true\n      #\n      # Perform hostname verification following RFC 6125.\n      #\n      # This method MUST be called after calling #connect to ensure that the\n      # hostname of a remote peer has been verified.\n      def post_connection_check(hostname)\n        if peer_cert.nil?\n          msg = \"Peer verification enabled, but no certificate received.\"\n          if using_anon_cipher?\n            msg += \" Anonymous cipher suite #{cipher[0]} was negotiated. \" \\\n                   \"Anonymous suites must be disabled to use peer verification.\"\n          end\n          raise SSLError, msg\n        end\n\n        unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)\n          raise SSLError, \"hostname \\\"#{hostname}\\\" does not match the server certificate\"\n        end\n        return true\n      end\n\n      # call-seq:\n      #   ssl.session -> aSession\n      #\n      # Returns the SSLSession object currently used, or nil if the session is\n      # not established.\n      def session\n        SSL::Session.new(self)\n      rescue SSL::Session::SessionError\n        nil\n      end\n\n      # Close the stream for reading.\n      # This method is ignored by OpenSSL as there is no reasonable way to\n      # implement it, but exists for compatibility with IO.\n      def close_read\n        # Unsupported and ignored.\n        # Just don't read any more.\n      end\n\n      # Closes the stream for writing. The behavior of this method depends on\n      # the version of OpenSSL and the TLS protocol in use.\n      #\n      # - Sends a 'close_notify' alert to the peer.\n      # - Does not wait for the peer's 'close_notify' alert in response.\n      #\n      # In TLS 1.2 and earlier:\n      # - On receipt of a 'close_notify' alert, responds with a 'close_notify'\n      #   alert of its own and close down the connection immediately,\n      #   discarding any pending writes.\n      #\n      # Therefore, on TLS 1.2, this method will cause the connection to be\n      # completely shut down. On TLS 1.3, the connection will remain open for\n      # reading only.\n      def close_write\n        stop\n      end\n\n      private\n\n      def using_anon_cipher?\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.ciphers = \"aNULL\"\n        ctx.ciphers.include?(cipher)\n      end\n\n      def client_cert_cb\n        @context.client_cert_cb\n      end\n\n      def session_new_cb\n        @context.session_new_cb\n      end\n\n      def session_get_cb\n        @context.session_get_cb\n      end\n\n      class << self\n\n        # call-seq:\n        #   open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)\n        #\n        # Creates a new instance of SSLSocket.\n        # _remote\\_host_ and _remote\\_port_ are used to open TCPSocket.\n        # If _local\\_host_ and _local\\_port_ are specified,\n        # then those parameters are used on the local end to establish the connection.\n        # If _context_ is provided,\n        # the SSL Sockets initial params will be taken from the context.\n        #\n        # === Examples\n        #\n        #   sock = OpenSSL::SSL::SSLSocket.open('localhost', 443)\n        #   sock.connect # Initiates a connection to localhost:443\n        #\n        # with SSLContext:\n        #\n        #   ctx = OpenSSL::SSL::SSLContext.new\n        #   sock = OpenSSL::SSL::SSLSocket.open('localhost', 443, context: ctx)\n        #   sock.connect # Initiates a connection to localhost:443 with SSLContext\n        def open(remote_host, remote_port, local_host=nil, local_port=nil, context: nil)\n          sock = ::TCPSocket.open(remote_host, remote_port, local_host, local_port)\n          if context.nil?\n            return OpenSSL::SSL::SSLSocket.new(sock)\n          else\n            return OpenSSL::SSL::SSLSocket.new(sock, context)\n          end\n        end\n      end\n    end\n\n    ##\n    # SSLServer represents a TCP/IP server socket with Secure Sockets Layer.\n    class SSLServer\n      include SocketForwarder\n      # When true then #accept works exactly the same as TCPServer#accept\n      attr_accessor :start_immediately\n\n      # Creates a new instance of SSLServer.\n      # * _srv_ is an instance of TCPServer.\n      # * _ctx_ is an instance of OpenSSL::SSL::SSLContext.\n      def initialize(svr, ctx)\n        @svr = svr\n        @ctx = ctx\n        unless ctx.session_id_context\n          # see #6137 - session id may not exceed 32 bytes\n          prng = ::Random.new($0.hash)\n          session_id = prng.bytes(16).unpack1('H*')\n          @ctx.session_id_context = session_id\n        end\n        @start_immediately = true\n      end\n\n      # Returns the TCPServer passed to the SSLServer when initialized.\n      def to_io\n        @svr\n      end\n\n      # See TCPServer#listen for details.\n      def listen(backlog=Socket::SOMAXCONN)\n        @svr.listen(backlog)\n      end\n\n      # See BasicSocket#shutdown for details.\n      def shutdown(how=Socket::SHUT_RDWR)\n        @svr.shutdown(how)\n      end\n\n      # Works similar to TCPServer#accept.\n      def accept\n        # Socket#accept returns [socket, addrinfo].\n        # TCPServer#accept returns a socket.\n        # The following comma strips addrinfo.\n        sock, = @svr.accept\n        begin\n          ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)\n          ssl.sync_close = true\n          ssl.accept if @start_immediately\n          ssl\n        rescue Exception => ex\n          if ssl\n            ssl.close\n          else\n            sock.close\n          end\n          raise ex\n        end\n      end\n\n      # See IO#close for details.\n      def close\n        @svr.close\n      end\n    end\n  end\nend\n\nend\n"
  },
  {
    "path": "lib/openssl/version.rb",
    "content": "# frozen_string_literal: true\n\nmodule OpenSSL\n  # The version string of Ruby/OpenSSL.\n  VERSION = \"4.0.1\"\nend\n"
  },
  {
    "path": "lib/openssl/x509.rb",
    "content": "# frozen_string_literal: true\n#--\n# = Ruby-space definitions that completes C-space funcs for X509 and subclasses\n#\n# = Info\n# 'OpenSSL for Ruby 2' project\n# Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>\n# All rights reserved.\n#\n# = Licence\n# This program is licensed under the same licence as Ruby.\n# (See the file 'COPYING'.)\n#++\n\nrequire_relative 'marshal'\n\nmodule OpenSSL\n  module X509\n    class ExtensionFactory\n      def create_extension(*arg)\n        if arg.size > 1\n          create_ext(*arg)\n        else\n          send(\"create_ext_from_\"+arg[0].class.name.downcase, arg[0])\n        end\n      end\n\n      def create_ext_from_array(ary)\n        raise ExtensionError, \"unexpected array form\" if ary.size > 3\n        create_ext(ary[0], ary[1], ary[2])\n      end\n\n      def create_ext_from_string(str) # \"oid = critical, value\"\n        oid, value = str.split(/=/, 2)\n        oid.strip!\n        value.strip!\n        create_ext(oid, value)\n      end\n\n      def create_ext_from_hash(hash)\n        create_ext(hash[\"oid\"], hash[\"value\"], hash[\"critical\"])\n      end\n    end\n\n    class Extension\n      include OpenSSL::Marshal\n\n      def ==(other)\n        return false unless Extension === other\n        to_der == other.to_der\n      end\n\n      def to_s # \"oid = critical, value\"\n        str = self.oid\n        str << \" = \"\n        str << \"critical, \" if self.critical?\n        str << self.value.gsub(/\\n/, \", \")\n      end\n\n      def to_h # {\"oid\"=>sn|ln, \"value\"=>value, \"critical\"=>true|false}\n        {\"oid\"=>self.oid,\"value\"=>self.value,\"critical\"=>self.critical?}\n      end\n\n      def to_a\n        [ self.oid, self.value, self.critical? ]\n      end\n\n      module Helpers\n        def find_extension(oid)\n          extensions.find { |e| e.oid == oid }\n        end\n      end\n\n      module SubjectKeyIdentifier\n        include Helpers\n\n        # Get the subject's key identifier from the subjectKeyIdentifier\n        # exteension, as described in RFC5280 Section 4.2.1.2.\n        #\n        # Returns the binary String key identifier or nil or raises\n        # ASN1::ASN1Error.\n        def subject_key_identifier\n          ext = find_extension(\"subjectKeyIdentifier\")\n          return nil if ext.nil?\n\n          ski_asn1 = ASN1.decode(ext.value_der)\n          if ext.critical? || ski_asn1.tag_class != :UNIVERSAL || ski_asn1.tag != ASN1::OCTET_STRING\n            raise ASN1::ASN1Error, \"invalid extension\"\n          end\n\n          ski_asn1.value\n        end\n      end\n\n      module AuthorityKeyIdentifier\n        include Helpers\n\n        # Get the issuing certificate's key identifier from the\n        # authorityKeyIdentifier extension, as described in RFC5280\n        # Section 4.2.1.1\n        #\n        # Returns the binary String keyIdentifier or nil or raises\n        # ASN1::ASN1Error.\n        def authority_key_identifier\n          ext = find_extension(\"authorityKeyIdentifier\")\n          return nil if ext.nil?\n\n          aki_asn1 = ASN1.decode(ext.value_der)\n          if ext.critical? || aki_asn1.tag_class != :UNIVERSAL || aki_asn1.tag != ASN1::SEQUENCE\n            raise ASN1::ASN1Error, \"invalid extension\"\n          end\n\n          key_id = aki_asn1.value.find do |v|\n            v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0\n          end\n\n          key_id.nil? ? nil : key_id.value\n        end\n      end\n\n      module CRLDistributionPoints\n        include Helpers\n\n        # Get the distributionPoint fullName URI from the certificate's CRL\n        # distribution points extension, as described in RFC 5280 Section\n        # 4.2.1.13.\n        #\n        # Returns an array of strings or nil or raises ASN1::ASN1Error.\n        def crl_uris\n          ext = find_extension(\"crlDistributionPoints\")\n          return nil if ext.nil?\n\n          cdp_asn1 = ASN1.decode(ext.value_der)\n          if cdp_asn1.tag_class != :UNIVERSAL || cdp_asn1.tag != ASN1::SEQUENCE\n            raise ASN1::ASN1Error, \"invalid extension\"\n          end\n\n          crl_uris = cdp_asn1.flat_map do |crl_distribution_point|\n            distribution_point = crl_distribution_point.value.find do |v|\n              v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0\n            end\n            full_name = distribution_point&.value&.find do |v|\n              v.tag_class == :CONTEXT_SPECIFIC && v.tag == 0\n            end\n            full_name&.value&.select do |v|\n              v.tag_class == :CONTEXT_SPECIFIC && v.tag == 6 # uniformResourceIdentifier\n            end\n          end\n\n          crl_uris.empty? ? nil : crl_uris.map(&:value)\n        end\n      end\n\n      module AuthorityInfoAccess\n        include Helpers\n\n        # Get the information and services for the issuer from the certificate's\n        # authority information access extension exteension, as described in RFC5280\n        # Section 4.2.2.1.\n        #\n        # Returns an array of strings or nil or raises ASN1::ASN1Error.\n        def ca_issuer_uris\n          aia_asn1 = parse_aia_asn1\n          return nil if aia_asn1.nil?\n\n          ca_issuer = aia_asn1.value.select do |authority_info_access|\n            authority_info_access.value.first.value == \"caIssuers\"\n          end\n\n          ca_issuer&.map(&:value)&.map(&:last)&.map(&:value)\n        end\n\n        # Get the URIs for OCSP from the certificate's authority information access\n        # extension exteension, as described in RFC5280 Section 4.2.2.1.\n        #\n        # Returns an array of strings or nil or raises ASN1::ASN1Error.\n        def ocsp_uris\n          aia_asn1 = parse_aia_asn1\n          return nil if aia_asn1.nil?\n\n          ocsp = aia_asn1.value.select do |authority_info_access|\n            authority_info_access.value.first.value == \"OCSP\"\n          end\n\n          ocsp&.map(&:value)&.map(&:last)&.map(&:value)\n        end\n\n        private\n\n          def parse_aia_asn1\n            ext = find_extension(\"authorityInfoAccess\")\n            return nil if ext.nil?\n\n            aia_asn1 = ASN1.decode(ext.value_der)\n            if ext.critical? || aia_asn1.tag_class != :UNIVERSAL || aia_asn1.tag != ASN1::SEQUENCE\n              raise ASN1::ASN1Error, \"invalid extension\"\n            end\n\n            aia_asn1\n          end\n      end\n    end\n\n    class Name\n      include OpenSSL::Marshal\n\n      module RFC2253DN\n        Special = ',=+<>#;'\n        HexChar = /[0-9a-fA-F]/\n        HexPair = /#{HexChar}#{HexChar}/\n        HexString = /#{HexPair}+/\n        Pair = /\\\\(?:[#{Special}]|\\\\|\"|#{HexPair})/\n        StringChar = /[^\\\\\"#{Special}]/\n        QuoteChar = /[^\\\\\"]/\n        AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\\.[0-9]+)*/\n        AttributeValue = /\n          (?![\"#])((?:#{StringChar}|#{Pair})*)|\n          \\#(#{HexString})|\n          \"((?:#{QuoteChar}|#{Pair})*)\"\n        /x\n        TypeAndValue = /\\A(#{AttributeType})=#{AttributeValue}/\n\n        module_function\n\n        def expand_pair(str)\n          return nil unless str\n          return str.gsub(Pair){\n            pair = $&\n            case pair.size\n            when 2 then pair[1,1]\n            when 3 then Integer(\"0x#{pair[1,2]}\").chr\n            else raise OpenSSL::X509::NameError, \"invalid pair: #{str}\"\n            end\n          }\n        end\n\n        def expand_hexstring(str)\n          return nil unless str\n          der = str.gsub(HexPair){$&.to_i(16).chr }\n          a1 = OpenSSL::ASN1.decode(der)\n          return a1.value, a1.tag\n        end\n\n        def expand_value(str1, str2, str3)\n          value = expand_pair(str1)\n          value, tag = expand_hexstring(str2) unless value\n          value = expand_pair(str3) unless value\n          return value, tag\n        end\n\n        def scan(dn)\n          str = dn\n          ary = []\n          while true\n            if md = TypeAndValue.match(str)\n              remain = md.post_match\n              type = md[1]\n              value, tag = expand_value(md[2], md[3], md[4]) rescue nil\n              if value\n                type_and_value = [type, value]\n                type_and_value.push(tag) if tag\n                ary.unshift(type_and_value)\n                if remain.length > 2 && remain[0] == ?,\n                  str = remain[1..-1]\n                  next\n                elsif remain.length > 2 && remain[0] == ?+\n                  raise OpenSSL::X509::NameError,\n                    \"multi-valued RDN is not supported: #{dn}\"\n                elsif remain.empty?\n                  break\n                end\n              end\n            end\n            msg_dn = dn[0, dn.length - str.length] + \" =>\" + str\n            raise OpenSSL::X509::NameError, \"malformed RDN: #{msg_dn}\"\n          end\n          return ary\n        end\n      end\n\n      class << self\n        # Parses the UTF-8 string representation of a distinguished name,\n        # according to RFC 2253.\n        #\n        # See also #to_utf8 for the opposite operation.\n        def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE)\n          ary = OpenSSL::X509::Name::RFC2253DN.scan(str)\n          self.new(ary, template)\n        end\n\n        # Parses the string representation of a distinguished name. Two\n        # different forms are supported:\n        #\n        # - \\OpenSSL format (<tt>X509_NAME_oneline()</tt>) used by\n        #   <tt>#to_s</tt>. For example: <tt>/DC=com/DC=example/CN=nobody</tt>\n        # - \\OpenSSL format (<tt>X509_NAME_print()</tt>)\n        #   used by <tt>#to_s(OpenSSL::X509::Name::COMPAT)</tt>. For example:\n        #   <tt>DC=com, DC=example, CN=nobody</tt>\n        #\n        # Neither of them is standardized and has quirks and inconsistencies\n        # in handling of escaped characters or multi-valued RDNs.\n        #\n        # Use of this method is discouraged in new applications. See\n        # Name.parse_rfc2253 and #to_utf8 for the alternative.\n        def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE)\n          if str.start_with?(\"/\")\n            # /A=B/C=D format\n            ary = str[1..-1].split(\"/\").map { |i| i.split(\"=\", 2) }\n          else\n            # Comma-separated\n            ary = str.split(\",\").map { |i| i.strip.split(\"=\", 2) }\n          end\n          self.new(ary, template)\n        end\n\n        alias parse parse_openssl\n      end\n\n      def pretty_print(q)\n        q.object_group(self) {\n          q.text ' '\n          q.text to_s(OpenSSL::X509::Name::RFC2253)\n        }\n      end\n    end\n\n    class Attribute\n      include OpenSSL::Marshal\n\n      def ==(other)\n        return false unless Attribute === other\n        to_der == other.to_der\n      end\n    end\n\n    class StoreContext\n      def cleanup\n        warn \"(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement\" if $VERBOSE\n      end\n    end\n\n    class Certificate\n      include OpenSSL::Marshal\n      include Extension::SubjectKeyIdentifier\n      include Extension::AuthorityKeyIdentifier\n      include Extension::CRLDistributionPoints\n      include Extension::AuthorityInfoAccess\n\n      def inspect\n        \"#<#{self.class}: \" \\\n          \"subject=#{subject.inspect}, \" \\\n          \"issuer=#{issuer.inspect}, \" \\\n          \"serial=#{serial.inspect}, \" \\\n          \"not_before=#{not_before.inspect rescue \"(error)\"}, \" \\\n          \"not_after=#{not_after.inspect rescue \"(error)\"}>\"\n      end\n\n      def pretty_print(q)\n        q.object_group(self) {\n          q.breakable\n          q.text 'subject='; q.pp self.subject; q.text ','; q.breakable\n          q.text 'issuer='; q.pp self.issuer; q.text ','; q.breakable\n          q.text 'serial='; q.pp self.serial; q.text ','; q.breakable\n          q.text 'not_before='; q.pp self.not_before; q.text ','; q.breakable\n          q.text 'not_after='; q.pp self.not_after\n        }\n      end\n\n      def self.load_file(path)\n        load(File.binread(path))\n      end\n    end\n\n    class CRL\n      include OpenSSL::Marshal\n      include Extension::AuthorityKeyIdentifier\n\n      def ==(other)\n        return false unless CRL === other\n        to_der == other.to_der\n      end\n    end\n\n    class Revoked\n      def ==(other)\n        return false unless Revoked === other\n        to_der == other.to_der\n      end\n    end\n\n    class Request\n      include OpenSSL::Marshal\n\n      def ==(other)\n        return false unless Request === other\n        to_der == other.to_der\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/openssl.rb",
    "content": "# frozen_string_literal: true\n=begin\n= Info\n  'OpenSSL for Ruby 2' project\n  Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>\n  All rights reserved.\n\n= Licence\n  This program is licensed under the same licence as Ruby.\n  (See the file 'COPYING'.)\n=end\n\nrequire 'openssl.so'\n\nrequire_relative 'openssl/bn'\nrequire_relative 'openssl/cipher'\nrequire_relative 'openssl/digest'\nrequire_relative 'openssl/hmac'\nrequire_relative 'openssl/pkcs5'\nrequire_relative 'openssl/pkey'\nrequire_relative 'openssl/ssl'\nrequire_relative 'openssl/version'\nrequire_relative 'openssl/x509'\n\nmodule OpenSSL\n  # :call-seq:\n  #    OpenSSL.secure_compare(string, string) -> true or false\n  #\n  # Constant time memory comparison. Inputs are hashed using SHA-256 to mask\n  # the length of the secret. Returns +true+ if the strings are identical,\n  # +false+ otherwise.\n  #\n  # This method is expensive due to the SHA-256 hashing. In most cases, where\n  # the input lengths are known to be equal or are not sensitive,\n  # OpenSSL.fixed_length_secure_compare should be used instead.\n  def self.secure_compare(a, b)\n    hashed_a = OpenSSL::Digest.digest('SHA256', a)\n    hashed_b = OpenSSL::Digest.digest('SHA256', b)\n    OpenSSL.fixed_length_secure_compare(hashed_a, hashed_b) && a == b\n  end\nend\n"
  },
  {
    "path": "openssl.gemspec",
    "content": "Gem::Specification.new do |spec|\n  spec.name          = \"openssl\"\n  spec.version       = \"4.0.1\"\n  spec.authors       = [\"Martin Bosslet\", \"SHIBATA Hiroshi\", \"Zachary Scott\", \"Kazuki Yamaguchi\"]\n  spec.email         = [\"ruby-core@ruby-lang.org\"]\n  spec.summary       = %q{SSL/TLS and general-purpose cryptography for Ruby}\n  spec.description   = %q{OpenSSL for Ruby provides access to SSL/TLS and general-purpose cryptography based on the OpenSSL library.}\n  spec.homepage      = \"https://github.com/ruby/openssl\"\n  spec.licenses      = [\"Ruby\", \"BSD-2-Clause\"]\n\n  if Gem::Platform === spec.platform and spec.platform =~ 'java' or RUBY_ENGINE == 'jruby'\n    spec.platform    = \"java\"\n    spec.files       = []\n    spec.add_runtime_dependency('jruby-openssl', '~> 0.14')\n  else\n    spec.files         = Dir.glob([\"lib/**/*.rb\", \"ext/**/*.{c,h,rb}\", \"*.md\"], base: File.expand_path(\"..\", __FILE__)) +\n                         [\"BSDL\", \"COPYING\"]\n    spec.require_paths = [\"lib\"]\n    spec.extensions    = [\"ext/openssl/extconf.rb\"]\n  end\n\n  spec.extra_rdoc_files = Dir[\"*.md\"]\n  spec.rdoc_options = [\"--main\", \"README.md\"]\n\n  spec.required_ruby_version = \">= 2.7.0\"\n\n  spec.metadata[\"msys2_mingw_dependencies\"] = \"openssl\"\nend\n"
  },
  {
    "path": "sample/c_rehash.rb",
    "content": "#!/usr/bin/env ruby\n\nrequire 'openssl'\n\nclass CHashDir\n  include Enumerable\n\n  def initialize(dirpath)\n    @dirpath = dirpath\n    @fingerprint_cache = @cert_cache = @crl_cache = nil\n  end\n\n  def hash_dir(silent = false)\n    # ToDo: Should lock the directory...\n    @silent = silent\n    @fingerprint_cache = Hash.new\n    @cert_cache = Hash.new\n    @crl_cache = Hash.new\n    do_hash_dir\n  end\n\n  def get_certs(name = nil)\n    if name\n      @cert_cache[hash_name(name)]\n    else\n      @cert_cache.values.flatten\n    end\n  end\n\n  def get_crls(name = nil)\n    if name\n      @crl_cache[hash_name(name)]\n    else\n      @crl_cache.values.flatten\n    end\n  end\n\n  def delete_crl(crl)\n    File.unlink(crl_filename(crl))\n    hash_dir(true)\n  end\n\n  def add_crl(crl)\n    File.open(crl_filename(crl), \"w\") do |f|\n      f << crl.to_pem\n    end\n    hash_dir(true)\n  end\n\n  def load_pem_file(filepath)\n    str = File.read(filepath)\n    begin\n      OpenSSL::X509::Certificate.new(str)\n    rescue\n      begin\n        OpenSSL::X509::CRL.new(str)\n      rescue\n        begin\n          OpenSSL::X509::Request.new(str)\n        rescue\n          nil\n        end\n      end\n    end\n  end\n\nprivate\n\n  def crl_filename(crl)\n    path(hash_name(crl.issuer)) + '.pem'\n  end\n\n  def do_hash_dir\n    Dir.chdir(@dirpath) do\n      delete_symlink\n      Dir.glob('*.pem') do |pemfile|\n        cert = load_pem_file(pemfile)\n        case cert\n        when OpenSSL::X509::Certificate\n          link_hash_cert(pemfile, cert)\n        when OpenSSL::X509::CRL\n          link_hash_crl(pemfile, cert)\n        else\n          STDERR.puts(\"WARNING: #{pemfile} does not contain a certificate or CRL: skipping\") unless @silent\n        end\n      end\n    end\n  end\n\n  def delete_symlink\n    Dir.entries(\".\").each do |entry|\n      next unless /^[\\da-f]+\\.r{0,1}\\d+$/ =~ entry\n      File.unlink(entry) if FileTest.symlink?(entry)\n    end\n  end\n\n  def link_hash_cert(org_filename, cert)\n    name_hash = hash_name(cert.subject)\n    fingerprint = fingerprint(cert.to_der)\n    filepath = link_hash(org_filename, name_hash, fingerprint) { |idx|\n      \"#{name_hash}.#{idx}\"\n    }\n    unless filepath\n      unless @silent\n        STDERR.puts(\"WARNING: Skipping duplicate certificate #{org_filename}\")\n      end\n    else\n      (@cert_cache[name_hash] ||= []) << path(filepath)\n    end\n  end\n\n  def link_hash_crl(org_filename, crl)\n    name_hash = hash_name(crl.issuer)\n    fingerprint = fingerprint(crl.to_der)\n    filepath = link_hash(org_filename, name_hash, fingerprint) { |idx|\n      \"#{name_hash}.r#{idx}\"\n    }\n    unless filepath\n      unless @silent\n        STDERR.puts(\"WARNING: Skipping duplicate CRL #{org_filename}\")\n      end\n    else\n      (@crl_cache[name_hash] ||= []) << path(filepath)\n    end\n  end\n\n  def link_hash(org_filename, name, fingerprint)\n    idx = 0\n    filepath = nil\n    while true\n      filepath = yield(idx)\n      break unless FileTest.symlink?(filepath) or FileTest.exist?(filepath)\n      if @fingerprint_cache[filepath] == fingerprint\n        return false\n      end\n      idx += 1\n    end\n    STDOUT.puts(\"#{org_filename} => #{filepath}\") unless @silent\n    symlink(org_filename, filepath)\n    @fingerprint_cache[filepath] = fingerprint\n    filepath\n  end\n\n  def symlink(from, to)\n    begin\n      File.symlink(from, to)\n    rescue\n      File.open(to, \"w\") do |f|\n        f << File.read(from)\n      end\n    end\n  end\n\n  def path(filename)\n    File.join(@dirpath, filename)\n  end\n\n  def hash_name(name)\n    sprintf(\"%08x\", name.hash)\n  end\n\n  def fingerprint(der)\n    OpenSSL::Digest.hexdigest('MD5', der).upcase\n  end\nend\n\nif $0 == __FILE__\n  dirlist = ARGV\n  dirlist << '/usr/ssl/certs' if dirlist.empty?\n  dirlist.each do |dir|\n    CHashDir.new(dir).hash_dir\n  end\nend\n"
  },
  {
    "path": "sample/cert2text.rb",
    "content": "#!/usr/bin/env ruby\n\nrequire 'openssl'\n\ndef cert2text(cert_str)\n  [\n    OpenSSL::X509::Certificate,\n    OpenSSL::X509::CRL,\n    OpenSSL::X509::Request,\n  ].each do |klass|\n    begin\n      puts klass.new(cert_str).to_text\n      return\n    rescue\n    end\n  end\n  raise ArgumentError.new('Unknown format.')\nend\n\nif ARGV.empty?\n  cert2text(STDIN.read)\nelse\n  ARGV.each do |file|\n    cert2text(File.read(file))\n  end\nend\n"
  },
  {
    "path": "sample/certstore.rb",
    "content": "require 'c_rehash'\nrequire 'crlstore'\n\n\nclass CertStore\n  attr_reader :self_signed_ca\n  attr_reader :other_ca\n  attr_reader :ee\n  attr_reader :crl\n  attr_reader :request\n\n  def initialize(certs_dir)\n    @certs_dir = certs_dir\n    @c_store = CHashDir.new(@certs_dir)\n    @c_store.hash_dir(true)\n    @crl_store = CrlStore.new(@c_store)\n    @x509store = OpenSSL::X509::Store.new\n    @self_signed_ca = @other_ca = @ee = @crl = nil\n\n    # Uncomment this line to let OpenSSL to check CRL for each certs.\n    # @x509store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK | OpenSSL::X509::V_FLAG_CRL_CHECK_ALL\n\n    add_path\n    scan_certs\n  end\n\n  def generate_cert(filename)\n    @c_store.load_pem_file(filename)\n  end\n\n  def verify(cert)\n    error, crl_map = do_verify(cert)\n    if error\n      [[false, cert, crl_map[cert.subject], error]]\n    else\n      @x509store.chain.collect { |c| [true, c, crl_map[c.subject], nil] }\n    end\n  end\n\n  def match_cert(cert1, cert2)\n    (cert1.issuer.cmp(cert2.issuer) == 0) and cert1.serial == cert2.serial\n  end\n\n  def is_ca?(cert)\n    case guess_cert_type(cert)\n    when CERT_TYPE_SELF_SIGNED\n      true\n    when CERT_TYPE_OTHER\n      true\n    else\n      false\n    end\n  end\n\n  def scan_certs\n    @self_signed_ca = []\n    @other_ca = []\n    @ee = []\n    @crl = []\n    @request = []\n    load_certs\n  end\n\nprivate\n\n  def add_path\n    @x509store.add_path(@certs_dir)\n  end\n\n  def do_verify(cert)\n    error_map = {}\n    crl_map = {}\n    result = @x509store.verify(cert) do |ok, ctx|\n      cert = ctx.current_cert\n      if ctx.current_crl\n        crl_map[cert.subject] = true\n      end\n      if ok\n        if !ctx.current_crl\n          if crl = @crl_store.find_crl(cert)\n            crl_map[cert.subject] = true\n            if crl.revoked.find { |revoked| revoked.serial == cert.serial }\n              ok = false\n              error_string = 'certification revoked'\n            end\n          end\n        end\n      end\n      error_map[cert.subject] = error_string if error_string\n      ok\n    end\n    error = if result\n      nil\n    else\n      error_map[cert.subject] || @x509store.error_string\n    end\n    return error, crl_map\n  end\n\n  def load_certs\n    @c_store.get_certs.each do |certfile|\n      cert = generate_cert(certfile)\n      case guess_cert_type(cert)\n      when CERT_TYPE_SELF_SIGNED\n        @self_signed_ca << cert\n      when CERT_TYPE_OTHER\n        @other_ca << cert\n      when CERT_TYPE_EE\n        @ee << cert\n      else\n        raise \"Unknown cert type.\"\n      end\n    end\n    @c_store.get_crls.each do |crlfile|\n      @crl << generate_cert(crlfile)\n    end\n  end\n\n  CERT_TYPE_SELF_SIGNED = 0\n  CERT_TYPE_OTHER = 1\n  CERT_TYPE_EE = 2\n  def guess_cert_type(cert)\n    ca = self_signed = is_cert_self_signed(cert)\n    cert.extensions.each do |ext|\n      # Ignores criticality of extensions.  It's 'guess'ing.\n      case ext.oid\n      when 'basicConstraints'\n        /CA:(TRUE|FALSE), pathlen:(\\d+)/ =~ ext.value\n        ca = ($1 == 'TRUE') unless ca\n      when 'keyUsage'\n        usage = ext.value.split(/\\s*,\\s*/)\n        ca = usage.include?('Certificate Sign') unless ca\n      when 'nsCertType'\n        usage = ext.value.split(/\\s*,\\s*/)\n        ca = usage.include?('SSL CA') unless ca\n      end\n    end\n    if ca\n      if self_signed\n        CERT_TYPE_SELF_SIGNED\n      else\n        CERT_TYPE_OTHER\n      end\n    else\n      CERT_TYPE_EE\n    end\n  end\n\n  def is_cert_self_signed(cert)\n    # cert.subject.cmp(cert.issuer) == 0\n    cert.subject.to_s == cert.issuer.to_s\n  end\nend\n\n\nif $0 == __FILE__\n  c = CertStore.new(\"trust_certs\")\nend\n"
  },
  {
    "path": "sample/cipher.rb",
    "content": "#!/usr/bin/env ruby\nrequire 'openssl'\n\ndef crypt_by_password(alg, pass, salt, text)\n  puts \"--Setup--\"\n  puts %(cipher alg:    \"#{alg}\")\n  puts %(plain text:    \"#{text}\")\n  puts %(password:      \"#{pass}\")\n  puts %(salt:          \"#{salt}\")\n  puts\n\n  puts \"--Encrypting--\"\n  enc = OpenSSL::Cipher.new(alg)\n  enc.encrypt\n  enc.pkcs5_keyivgen(pass, salt)\n  cipher =  enc.update(text)\n  cipher << enc.final\n  puts %(encrypted text: #{cipher.inspect})\n  puts\n\n  puts \"--Decrypting--\"\n  dec = OpenSSL::Cipher.new(alg)\n  dec.decrypt\n  dec.pkcs5_keyivgen(pass, salt)\n  plain =  dec.update(cipher)\n  plain << dec.final\n  puts %(decrypted text: \"#{plain}\")\n  puts\nend\n\ndef ciphers\n  ciphers = OpenSSL::Cipher.ciphers.sort\n  ciphers.each{|i|\n    if i.upcase != i && ciphers.include?(i.upcase)\n      ciphers.delete(i)\n    end\n  }\n  return ciphers\nend\n\nputs \"Supported ciphers in #{OpenSSL::OPENSSL_VERSION}:\"\nciphers.each_with_index{|name, i|\n  printf(\"%-15s\", name)\n  puts if (i + 1) % 5 == 0\n}\nputs\nputs\n\nalg  = ARGV.shift || ciphers.first\npass = \"secret password\"\nsalt = \"8 octets\"        # or nil\ntext = \"abcdefghijklmnopqrstuvwxyz\"\n\ncrypt_by_password(alg, pass, salt, text)\n"
  },
  {
    "path": "sample/crlstore.rb",
    "content": "begin\n  require 'http-access2'\nrescue LoadError\n  STDERR.puts(\"Cannot load http-access2.  CRL might not be fetched.\")\nend\nrequire 'c_rehash'\n\n\nclass CrlStore\n  def initialize(c_store)\n    @c_store = c_store\n    @c_store.hash_dir(true)\n  end\n\n  def find_crl(cert)\n    do_find_crl(cert)\n  end\n\nprivate\n\n  def do_find_crl(cert)\n    unless ca = find_ca(cert)\n      return nil\n    end\n    unless crlfiles = @c_store.get_crls(ca.subject)\n      if crl = renew_crl(cert, ca)\n        @c_store.add_crl(crl)\n        return crl\n      end\n      return nil\n    end\n    crlfiles.each do |crlfile|\n      next unless crl = load_crl(crlfile)\n      if crl.next_update < Time.now\n        if new_crl = renew_crl(cert, ca)\n          @c_store.delete_crl(crl)\n          @c_store.add_crl(new_crl)\n          crl = new_crl\n        end\n      end\n      if check_valid(crl, ca)\n        return crl\n      end\n    end\n    nil\n  end\n\n  def find_ca(cert)\n    @c_store.get_certs(cert.issuer).each do |cafile|\n      ca = load_cert(cafile)\n      if cert.verify(ca.public_key)\n        return ca\n      end\n    end\n    nil\n  end\n\n  def fetch(location)\n    if /\\AURI:(.*)\\z/ =~ location\n      begin\n        c = HTTPAccess2::Client.new(ENV['http_proxy'] || ENV['HTTP_PROXY'])\n        c.get_content($1)\n      rescue NameError, StandardError\n        nil\n      end\n    else\n      nil\n    end\n  end\n\n  def load_cert(certfile)\n    load_cert_str(File.read(certfile))\n  end\n\n  def load_crl(crlfile)\n    load_crl_str(File.read(crlfile))\n  end\n\n  def load_cert_str(cert_str)\n    OpenSSL::X509::Certificate.new(cert_str)\n  end\n\n  def load_crl_str(crl_str)\n    OpenSSL::X509::CRL.new(crl_str)\n  end\n\n  def check_valid(crl, ca)\n    unless crl.verify(ca.public_key)\n      return false\n    end\n    crl.last_update <= Time.now\n  end\n\n  RE_CDP = /\\AcrlDistributionPoints\\z/\n  def get_cdp(cert)\n    if cdp_ext = cert.extensions.find { |ext| RE_CDP =~ ext.oid }\n      cdp_ext.value.chomp\n    else\n      false\n    end\n  end\n\n  def renew_crl(cert, ca)\n    if cdp = get_cdp(cert)\n      if new_crl_str = fetch(cdp)\n        new_crl = load_crl_str(new_crl_str)\n        if check_valid(new_crl, ca)\n          return new_crl\n        end\n      end\n    end\n    false\n  end\nend\n\nif $0 == __FILE__\n  dir = \"trust_certs\"\n  c_store = CHashDir.new(dir)\n  s = CrlStore.new(c_store)\n  c = OpenSSL::X509::Certificate.new(File.read(\"cert_store/google_codesign.pem\"))\n  p s.find_crl(c)\nend\n"
  },
  {
    "path": "sample/echo_cli.rb",
    "content": "#!/usr/bin/env ruby\n\nrequire 'socket'\nrequire 'openssl'\nrequire 'optparse'\n\noptions = ARGV.getopts(\"p:c:k:C:\")\n\nhost      = ARGV[0] || \"localhost\"\nport      = options[\"p\"] || \"2000\"\ncert_file = options[\"c\"]\nkey_file  = options[\"k\"]\nca_path   = options[\"C\"]\n\nctx = OpenSSL::SSL::SSLContext.new()\nif cert_file && key_file\n  ctx.cert = OpenSSL::X509::Certificate.new(File::read(cert_file))\n  ctx.key  = OpenSSL::PKey.read(File::read(key_file))\nend\nif ca_path\n  ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n  ctx.ca_path = ca_path\nelse\n  $stderr.puts \"!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!\"\nend\n\ns = TCPSocket.new(host, port)\nssl = OpenSSL::SSL::SSLSocket.new(s, ctx)\nssl.connect # start SSL session\np ssl.peer_cert\nerrors = Hash.new\nOpenSSL::X509.constants.grep(/^V_(ERR_|OK)/).each do |name|\n  errors[OpenSSL::X509.const_get(name)] = name\nend\np errors[ssl.verify_result]\n\nssl.sync_close = true  # if true the underlying socket will be\n                       # closed in SSLSocket#close. (default: false)\nwhile line = $stdin.gets\n  ssl.write line\n  puts ssl.gets.inspect\nend\n\nssl.close\n"
  },
  {
    "path": "sample/echo_svr.rb",
    "content": "#!/usr/bin/env ruby\n\nrequire 'socket'\nrequire 'openssl'\nrequire 'optparse'\n\noptions = ARGV.getopts(\"p:c:k:C:\")\n\nport      = options[\"p\"] || \"2000\"\ncert_file = options[\"c\"]\nkey_file  = options[\"k\"]\nca_path   = options[\"C\"]\n\nif cert_file && key_file\n  cert = OpenSSL::X509::Certificate.new(File::read(cert_file))\n  key  = OpenSSL::PKey.read(File::read(key_file))\nelse\n  key = OpenSSL::PKey::RSA.new(2048){ print \".\" }\n  puts\n  cert = OpenSSL::X509::Certificate.new\n  cert.version = 2\n  cert.serial = 0\n  name = OpenSSL::X509::Name.new([[\"C\",\"JP\"],[\"O\",\"TEST\"],[\"CN\",\"localhost\"]])\n  cert.subject = name\n  cert.issuer = name\n  cert.not_before = Time.now\n  cert.not_after = Time.now + 3600\n  cert.public_key = key\n  ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)\n  cert.extensions = [\n    ef.create_extension(\"basicConstraints\",\"CA:FALSE\"),\n    ef.create_extension(\"subjectKeyIdentifier\",\"hash\"),\n    ef.create_extension(\"extendedKeyUsage\",\"serverAuth\"),\n    ef.create_extension(\"keyUsage\",\n                        \"keyEncipherment,dataEncipherment,digitalSignature\")\n  ]\n  ef.issuer_certificate = cert\n  cert.add_extension ef.create_extension(\"authorityKeyIdentifier\",\n                                         \"keyid:always,issuer:always\")\n  cert.sign(key, \"SHA1\")\nend\n\nctx = OpenSSL::SSL::SSLContext.new()\nctx.key = key\nctx.cert = cert\nif ca_path\n  ctx.verify_mode =\n    OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT\n  ctx.ca_path = ca_path\nelse\n  $stderr.puts \"!!! WARNING: PEER CERTIFICATE WON'T BE VERIFIED !!!\"\nend\n\ntcps = TCPServer.new(port)\nssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)\nloop do\n  ns = ssls.accept\n  puts \"connected from #{ns.peeraddr}\"\n  while line = ns.gets\n    puts line.inspect\n    ns.write line\n  end\n  puts \"connection closed\"\n  ns.close\nend\n"
  },
  {
    "path": "sample/gen_csr.rb",
    "content": "#!/usr/bin/env ruby\n\nrequire 'optparse'\nrequire 'openssl'\n\ndef usage\n  myname = File::basename($0)\n  $stderr.puts <<EOS\nUsage: #{myname} [--key keypair_file] name\n  name ... ex. /C=JP/O=RRR/OU=CA/CN=NaHi/emailAddress=nahi@example.org\nEOS\n  exit\nend\n\noptions = ARGV.getopts(nil, \"key:\", \"csrout:\", \"keyout:\")\nkeypair_file = options[\"key\"]\ncsrout = options[\"csrout\"] || \"csr.pem\"\nkeyout = options[\"keyout\"] || \"keypair.pem\"\n\n$stdout.sync = true\nname_str = ARGV.shift or usage()\nname = OpenSSL::X509::Name.parse(name_str)\n\nkeypair = nil\nif keypair_file\n  keypair = OpenSSL::PKey.read(File.read(keypair_file))\nelse\n  keypair = OpenSSL::PKey::RSA.new(2048) { putc \".\" }\n  puts\n  puts \"Writing #{keyout}...\"\n  File.open(keyout, \"w\", 0400) do |f|\n    f << keypair.to_pem\n  end\nend\n\nputs \"Generating CSR for #{name_str}\"\n\nreq = OpenSSL::X509::Request.new\nreq.version = 0\nreq.subject = name\nreq.public_key = keypair\nreq.sign(keypair, \"MD5\")\n\nputs \"Writing #{csrout}...\"\nFile.open(csrout, \"w\") do |f|\n  f << req.to_pem\nend\nputs req.to_text\nputs req.to_pem\n"
  },
  {
    "path": "sample/smime_read.rb",
    "content": "require 'optparse'\nrequire 'openssl'\n\noptions = ARGV.getopts(\"c:k:C:\")\n\ncert_file = options[\"c\"]\nkey_file  = options[\"k\"]\nca_path   = options[\"C\"]\n\ndata = $stdin.read\n\ncert = OpenSSL::X509::Certificate.new(File::read(cert_file))\nkey = OpenSSL::PKey::read(File::read(key_file))\np7enc = OpenSSL::PKCS7::read_smime(data)\ndata = p7enc.decrypt(key, cert)\n\nstore = OpenSSL::X509::Store.new\nstore.add_path(ca_path)\np7sig = OpenSSL::PKCS7::read_smime(data)\nif p7sig.verify([], store)\n  puts p7sig.data\nend\n"
  },
  {
    "path": "sample/smime_write.rb",
    "content": "require 'openssl'\nrequire 'optparse'\n\noptions = ARGV.getopts(\"c:k:r:\")\n\ncert_file = options[\"c\"]\nkey_file  = options[\"k\"]\nrcpt_file = options[\"r\"]\n\ncert = OpenSSL::X509::Certificate.new(File::read(cert_file))\nkey = OpenSSL::PKey::read(File::read(key_file))\n\ndata  = \"Content-Type: text/plain\\r\\n\"\ndata << \"\\r\\n\"\ndata << \"This is a clear-signed message.\\r\\n\"\n\np7sig  = OpenSSL::PKCS7::sign(cert, key, data, [], OpenSSL::PKCS7::DETACHED)\nsmime0 = OpenSSL::PKCS7::write_smime(p7sig)\n\nrcpt  = OpenSSL::X509::Certificate.new(File::read(rcpt_file))\np7enc = OpenSSL::PKCS7::encrypt([rcpt], smime0)\nprint OpenSSL::PKCS7::write_smime(p7enc)\n"
  },
  {
    "path": "sample/wget.rb",
    "content": "#!/usr/bin/env ruby\n\nrequire 'net/https'\nrequire 'optparse'\n\noptions = ARGV.getopts('C:')\n\ncert_store = options[\"C\"]\n\nuri = URI.parse(ARGV[0])\nif proxy = ENV['HTTP_PROXY']\n  prx_uri = URI.parse(proxy)\n  prx_host = prx_uri.host\n  prx_port = prx_uri.port\nend\n\nh = Net::HTTP.new(uri.host, uri.port, prx_host, prx_port)\nh.set_debug_output($stderr) if $DEBUG\nif uri.scheme == \"https\"\n  h.use_ssl = true\n  if cert_store\n    if File.directory?(cert_store)\n      h.ca_path = cert_store\n    else\n      h.ca_file = cert_store\n    end\n  end\nend\n\npath = uri.path.empty? ? \"/\" : uri.path\nh.get2(path){|resp|\n  STDERR.puts h.peer_cert.inspect if h.peer_cert\n  print resp.body\n}\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/dh-1.pem",
    "content": "-----BEGIN DH PARAMETERS-----\nMIICCAKCAgEAvRzXYxY6L2DjeYmm1eowtMDu1it3j+VwFr6s6PRWzc1apMtztr9G\nxZ2mYndUAJLgNLO3n2fUDCYVMB6ZkcekW8Siocof3xWiMA6wqZ6uw0dsE3q7ZX+6\nTLjgSjaXeGvjutvuEwVrFeaUi83bMgfXN8ToxIQVprIF35sYFt6fpbFATKfW7qqi\nP1pQkjmCskU4tztaWvlLh0qg85wuQGnpJaQT3gS30378i0IGbA0EBvJcSpTHYbLa\nnsdI9bfN/ZVgeolVMNMU9/n8R8vRhNPcHuciFwaqS656q+HavCIyxw/LfjSwwFvR\nTngCn0wytRErkzFIXnRKckh8/BpI4S+0+l1NkOwG4WJ55KJ/9OOdZW5o/QCp2bDi\nE0JN1EP/gkSom/prq8JR/yEqtsy99uc5nUxPmzv0IgdcFHZEfiQU7iRggEbx7qfQ\nVe55XksmmJInmpCy1bSabAEgIKp8Ckt5KLYZ0RgTXUhcEpsxEo6cuAwoSJT5o4Rp\nyG3xow2ozPcqZkvb+d2CHj1sc54w9BVFAjVANEKmRil/9WKz14bu3wxEhOPqC54n\nQojjLcoXSoT66ZUOQnYxTSiLtzoKGPy8cAVPbkBrXz2u2sj5gcvr1JjoGjdHm9/3\nqnqC8fsTz8UndKNIQC337o4K0833bQMzRGl1/qjbAPit2B7E3b6xTZMCAQI=\n-----END DH PARAMETERS-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/dh2048_ffdhe2048.pem",
    "content": "-----BEGIN DH PARAMETERS-----\nMIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\nYdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\nssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==\n-----END DH PARAMETERS-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/dsa2048.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIICXgIBADCCAjYGByqGSM44BAEwggIpAoIBAQDXZhJ/dQoWkQELzjzlx8FtIp96\nvoCYe5NY0H8j0jz7GyHpXt41+MteqkZK3/Ah+cNR9uG8iEYArAZ71LcWotfee2Gz\nxdxozr9bRt0POYhO2YIsfMpBrEskPsDH2g/2nFV8l4OJgxU2qZUrF4PN5ha+Mu6u\nsVtN8hjvAvnbf4Pxn0b8NN9f4PJncroUa8acv5WsV85E1RW7NYCefggU4LytYIHg\neuRF9eY9gVCX5MkUgW2xODHIYJhwk/+5lJxG7qUsSahD/nPHO/yoWgdVHq2DkdTq\nKYXkAxx2PJcTBOHTglhE6mgCbEKp8vcfElnBWyCT6QykclZiPXXD2JV829J/Ah0A\nvYa+/G/gUZiomyejVje6UsGoCc+vInxmovOL8QKCAQEAhnKEigYPw6u8JY7v5iGo\nYlz8qiMFYmaJCwevf3KCjWeEXuNO4OrKdfzkQl1tPuGLioYFfP1A2yGosjdUdLEB\n0JqnzlKxUp+G6RfBj+WYzbgc5hr7t0M+reAJh09/hDzqfxjcgiHstq7mpRXBP8Y7\niu27s7TRYJNSAYRvWcXNSBEUym3mHBBbZn7VszYooSrn60/iZ8I+VY1UF/fgqhbj\nJfaaZNQCDO9K3Vb3rsXoYd8+bOZIen9uHB+pNjMqhpl4waysqrlpGFeeqdxivH6S\nvkrHLs6/eWVMnS08RdcryoCrI3Bm8mMBKQglDwKLnWLfzG565qEhslzyCd/l9k9a\ncwQfAh0Ao8/g72fSFmo04FizM7DZJSIPqDLjfZu9hLvUFA==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/mldsa65-1.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIP/gIBADALBglghkgBZQMEAxIEgg/qMIIP5gQg6Xunp08Ia0w6d93rvBnXnlYf\nih3Z+9IDZSRIyAGfjbQEgg/A9DPSakjm2xFsVzCHpfwcUwP5dYpJGRYwG7/eSp8b\n/lJOHPmIHjOAC8jN3xS66UXcouWozGXbmieGjLzNs1HjBaJ0CEw51wQOuPLDg8nj\nPdesnqu5Ct1sNzqz0K57ixyEPrdPI+Vd7XDNaXfOytZ1d4+yFBC6cGpznQ9CiRYm\nPpFEgUZSg3QzFmB0hREkB4FHhTIUZlckclcxNRRTg4UFUIVTdTcThxVyJSFFInZl\nGEUnKAIEcXBUdmgwMQMhRngCFEIFBIB2BVRjEiEwI3FwAQJEEScySFh0UVdQExeB\nZDYgIUhlFUYxh1g2V2YRdohodCVgBXYIJRJCQHFGRiI0GGQENkgBFwUGNUeAMlh0\nZgMhIWRmhyhGVEeAUUOHVVKEZHU4BQdwMjEBIIcQeBYFZhKBdwFjBlQECCJEdoYT\nE3FXYlcECCNIZAF4cTaAQwYxBkd2YRE3FTIYRCYgF2SBUiBCJ1ImFjZSFDCIaAY1\nJ1ExVDRRVzFGgiUIV1UBCDcVFmcIM4OGeDIXEyZXaCFzBBeBFQQxcFeIJWBmJCdw\nhWMUdYFiNFAmMIEyKIRYIIeIgHA3AmNTElA3gwVmBUUHERE2AAJHUhQTJQAFAXhY\nQmYDdSZHWFhHQXUkRFBWViQ4VERRF1eEN0I2VzR1dUIxg1Uid2NmcDIWdBAzITEA\nAmJgh3JlgwIREgVoIiEoMCADEGSHFIGHUnJVU2I0CGRxaAR3JUVgAnJQOAQiZ2Vh\nOFM3MIEHUmFzQhcEdzSBhBcYVCgEKCIiWHUBhCVxhkBjRzUzJAhDQ2F3eGdUNTEj\nQQcjY3E3BnR2Q4cWIjJohyd2hCUzOIgSUodmIxY1AmaDFVBQEghncQQYQ2QIcjiB\nZWNQZGZFhHiBIQcXURQQAVg2RBQQd0aDgGQXE3Q4eHY1iERUVoUTcQIjcmh0UVci\nRhd4MRI0ZUVHNXEAIDQ2cVIGZYMiB1ZQQSYVMlZBQiAwQHJYCEUBExAjF4QwQBMT\ncjdGVCckJTBFJAcXREMzAlYmhRJXgEVSESFYAAJwFXRyKBZCQwcDIFQkJWUFB4gV\nF2GBiEcVEUAmcWEFREA4dEFDQwhFUQUIcHQRMRGHFTA2g0YmZxIiMjMjAQFgcHYF\nIgJlFyA4RhdRgWY1FVEhM4VoUhiIQkcIeCCFZIESZjVWFjNWQEZTNGUoBiR0cgFn\nhDNIAhIRdXQgaGBxNUdyBUIWAniAZIOHYTIyUYd0YXExBjEShGA1GBQ3FBZVEmEw\nEhhEJQNwRjUyQnSIAVNlQjKDdIEBQQhgdSdxc2RjEmRiFyY2RRYicjQCh3AhNSZo\nQzRlGDaGMzCIhRcjIocxN4cwM2gRA2WIN0NyaHR1NRVRAXIkFTR0J2NCCCEHKHYn\nFSYGF3QXBwhDYUZEJmdHEWAlBCIyVRFBR2NSNgJwZgBoAgMjcYQRNAFjI2ZVVgEE\nV3Y1eIREhFc1ABVEGGcUNGRnWAJYOAdlZmgWQlZncWJVNFNkBwOGRiAmJGQGNlIx\nNwNwZ3WBaGIBdiNlMEVXFwFkZRRCE3ZwFxgQWFKHVxOBdxJHJBhSF0d4IlAgIRUY\nUXdCWIQIKDGAhAIoVBAhdXU3AHKCiCBkF4KEhhRyU2JTIIdwdGYSCDcXIWM4QYIY\nNoCFNSESeBMnciUkMxV1RYNzYUSGggMIgWVCM3aAMRcCITMgKERIEjgiUkIlNoUT\nJkMjMzc3dxV1WGOCZRJSMzIhGIAgBEgicDM2CFclACBlBoYyhyNgJoOIExIoY3Qh\nEFRQhFYBZoJERhNoQCIUaAIARgiCQSUXYkUgR4RnYAczh0ECOCeGdBJXExNohzZH\nGFMAE2MAUUZ3NzF2FldoGCKEIzJzGDFHd3KAU4ZHUichAYUmEYVAdShYFlh3FIIl\nUzQYdScUdlAAglVjBiNCJYGBKHVTNEJBMBAQEFQhJSI0diJ0dFA3KBIAg2RxcXIA\ncWMBcoIEQBgAUBUyEDUwcQYTVwSCMjBCVEQiQWMThDhVE2YWZBNQhVZzY4cBhIZh\nIIBBQihmh4VgJjZkJ2J1VlAB5kLlGDaGXIOc++2QqMCGeB9FnTYpHFoSXQrOjQhS\ntfTln0rEelihhKhi3Bu8mdhyTSFZTShsQidqlN1/U50KnMTqII7r9QltUZqPH9sW\nCswVssxnVe1GAXY/LqJPN5DEN2ZEMoAgmxLbGYB5YdKID1lj5zquaCqpDUGDI/Wi\nzJ5xpFzn7nGJwedU2MBqcqlIVJg8VeIInkLL/v3y2uqD4+pewW8OewqosJOfBgjI\nRH1FXcdGbnqKJk1YZ8iwVMTNoU9U8gGDI5kk/dWWqqAdxaVrsmevmNRp6wtibFG6\nFxrSRb7hOP8IVv7TkMA+Cv4MRs0UhYJ2W8x0G0LxP4M+m3cAJkaHyHDda1NHjfTV\nzG9hWK8Ad7t+F9hw5++KBPlkW+/sX4eYpOlC/XjpMp1W6WIr9oIbRp6RXKNUuBXQ\n58uNAmq6peDenbwsmiBKG+RWntbMxtjOM9bo/JXMV9dIT/KIbljl2C/4TRbWy0D3\nKfZlvAHpiw2oH/vaLUFbIg7sK823keZA/uSFJ2KSPBVC6+AYX5tM/P/KKLJmFoVY\nU7h4F/SDCbOt5PJu9yg+fN6ftBT3a2723TAx7M8+WqPrvvOB5UFJRNCcpwnjqriz\n8ENLgoze5wm2sIk+QvB15tFG0n3+9eTOjD+q0dJDSxq5xAuAalBoFp7vSt2x1UO/\n4Nf/jXvJT2nXjR7QgtabQRzKqbP5lHVtL0BCJeGFlbGeuAGIfNuVY0809E66sWDo\nS18hNAfp9jKe0aU7MxGU6RvCB8vLK+cld/RzujyK8C307PJdzwCLEYIBMC3SvBcQ\n9CpJFuPIcEVoM1RiThw/l1MAaKJ3y73ekU5p+Dd2CN4P4pCDSiVj/PAOW1c7iA2A\nQBVuCfPMYJyW93toHaqpaZuD9VN3OKbtJvuMWCOIN59ERFvttv5CNQ01rhgCv3dZ\nkkkFrJsmFcwsgMW1JIGozMKywFzi9yDWUL6j/ZCc8xqkfP9fYPBBTcSsUvWV9Zq6\nAU22B9j6/EUP8crw0VViacbEJy2sJgIumEQiVlVNavorpPwjtWpVQFvsBrDm6X80\njk9H/yTKrrR6LaTH7999s/88jOLszmbX7Yt8VmMkkliml2rd6UqG9D6zq2xEj1IV\n6ZT2zhVe+wHNmpkr1kYTIVsLXrHNpCWEQeHscSCzz/lg+aOv8kSfFqGq2VFjxnts\n7Z88TjxzIOQk14Lzkgl0PCyHXau8i2bteCOimqRYEd3ihNcC8U9MXLYrOiv24oXM\nRpkzoHGOtZoAie6k1Xj6aDwIl2mTBHg5BF0A4U+d/z7wS8Gr9nEc574s9OyKAZn6\n5L/1GgpWa0e2buxn8fkPAMptY0773prqKqwvV/SWdvUJ4B4HLNLsU70+N4XAZlRS\n7saNkghBkrD/WobJQwa/9OWWa5Gw6Frurr0AmnBU+EN7u6niFwARsa9f1yjuW8IJ\ntLD7H+Yu2bGouHWpeoXQHwqFxl+me7rQ/ePvOYQk/SzlzvroaqAGECrDoHU3kzhn\nrhJLueA9b0j3u0/+CQaNOFPWb6GAjmafVWpBcXtOSkHVUXitclURlITEwe47tn+g\nXffSw3k1q3XBKkFkJQrgPa2IbpAWvFKA7rOInY/b8N/lCI0bZAei2OOR2/MLifkx\nF3L8daWXslp7QSlIjUXwtgdD6CwQsEui99dZvTYlSxzUKC9nsF0oPYxWpHAcuoCE\npQCR1CuyuGkDCaod2VNWqWOcZ5QXjEtbVHFO8qJdePJPKWV+0YcltaR4X5q2Pts9\n4a0SJMSM/tXrUi9g9RjjnB+F++rc4a5FrQ2r7FDXudk7NUEoJPyBvBDeowiSmXvv\nSHrL6WsQgf8n5sZxfA0uqs+8OMSLLNj72CSoBQMJNVJgYQkSyBuHl6Zk59+k/WeJ\nwX1qevXwaC6JrdF+naRcp16tNv+7230GPO1d3+X3zZOtAEuAzk6kw3da8Y15qZ5j\nFqzXPO8TsURyOf4Fp+kxpETSQ+mf8Do0hWzUYE8Cj2EFcwuE2Q7+c1ZHAFpQNk1j\nT4vR//yCYjO8/lY0yDV7iDzkT36twyvKZ/cMxC001RSNmtr3QNWWkRRDBWCSwnjW\n+cn408gCVFPwVUOBwUr6aOeUY+fCcvWnYPCDj7ggdS5wEoUk+xrk4v2kU2gAH/mp\nDqhFNouIcExoNW5j7j0w0YKnZtZJ9pviiM0EXS6vhk4ayxI2pi3VOqL2RhoNleAa\nbTcCQ71wOxqpp4khssLcOsUR8trpadlvZJ9sc1ksUfoOz/pMI9Yj0IWctbuiriJp\nl193X2sPzVMn3MaEt+XPrsX5wOogbQAfSJyY8pfCnZuhVLoZDpJADJxou0EhP+wH\np9yZc5GZosFgDJvTEhZfUmituLW4+op1FLJqA/LQSxBVz51OnmtzpgJLyR0ctTLG\n9CcYbFTrzltPlOTHVjVW4rD9jyoLjLdfUf9qG65qVpGBisV+wD+SI6P0x5rhN7Dt\nnC0YNZZ0cYyN24xw8Bxzcc9RkY8/MFfbTXOG43Uuh7fkPIdY2NQSUK2tkfiMdPgu\nzlR1HoZHBrCcsQXJH0OhbuJ6Uwzm340Upj4b/eykq+uUcVY8PAUHSg6mwKy+E4yp\nZa5Z5U50Kv9rFcE9Hwh09fGfdUrKTCFxoKrqfeW+ogTXJHQR5A41r9PP1l7/9Bp7\nP+UtdjJtAHzTO1r7/dckvghBslqhNBzA55wtWEmjMFh4Mm3lBMvBGrCelKPtaOrb\nCYlv4eqGZMEeE3VoEKO3QnXU/dqJvhwQhjCcgxPtOzm9eSrofTvXa4xIMKyuNF2z\nF6K0S5o3I+pBUInshXHWwN1pAT1R4FRYAUTv9mZbhLP+MWgPIMrdWWHAMDL5DeBH\nG4AT5RQbzIHjQ12fJq30m1LajjLlL+mF5og+plMgEGOCJMHZyT2NcNb7gFHWk2mh\nJmO/qxdXQ1FQ/oEf+gNmfgdlw/N6TY7PvmkVfdkhgp/zQLcGgJ33gj0gy4Jr284G\nEhmeOGQflVsMFDqrAgjCEEJSLl/+FXuDfJjTixyly/yTTJCAeiEXsSW4xDisYZyR\ndmEXPtx7eyelJjbsM2yMTNacvCA8TCywTqxYMlYF45kHhTrnQoMvx83U0vqB+ALA\nJsGGrYQZ3tx9j8ae27b0rkSrccFYhKCXI/mwEZcZ6SG3q6/PhHWQOaie2EkuVLDq\nYAK0ZjlTv0znE1OVN3ovKAqq8ga/y5tOKXREo/i/SRPj4aHel4Lky26+Nmm+t+E2\nCL3SBcqhBC45qIB27kdsqBsnCfSzm1fQsy6jivCEDneLTLNoltDyXunSwyLP/7HI\nqclQDtLzvC0mHUNlhcds4I20\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/mldsa65-2.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIP/gIBADALBglghkgBZQMEAxIEgg/qMIIP5gQgDdLfrcKpbcx2qbjvcE+SqUnW\n+y7uWok/WM51jtrhQGIEgg/Az2AAnia3lgXsNEHx5NtoKaslKSsMPpvhRGFlcTcT\nZFF3hKrybqvpUxtqF8nqPTy0geEN/k/k6rYHDIcaBfE5J65Xn8dwRbUSzpjSJVD7\naBv1qprz1pAAXMYcazKeqWCJxyy7u9opGuNMaJ7SHcqwQ1kZ4nWaxEua9JnXZ6aJ\nzGkVg3WFgnBFVFJjNwFRGGNDNjNVAUUgURZgiFhARkBIIIVFZkJ3UlaAFzBodRVj\nOGhnUHAyQkc0ZRQYVTUDAQcHNhVTInEyZ0hngkBRcmKFdxgjVShoRmAyRYRTMAFi\nKARRInZVhCMHhCQzcDh4hAd2V4UoVVGIIHclWFZXJVCDUXeFZ1YnIgcjgiJnU0BI\nEoFgEnZyF2OEUSUlJSNicSUChwFGJCglhnBCMUZWdAeACCVEVxVFYTRFQ3AyhkNo\ncwFSBAd0BGVBBlRyhVYQVyNHVSJmYhNhBXaFMIUTEEJYYFhxhWN0IQNYQQdHMHMC\nFTM0cUVGcnBlCAZSYQM4Unh0NTCBIlAHEYMmYzUmQ1cIBIKENGYlKAYnMSYwBFAy\nIiMWVBMQeAJQVRJBh2A1ImB3cYVgd2QhJSUVg3VYd0VxMmQhIhB4YQJTIoFiBkcj\nQgIBVEQIgXaABoNAOGUkcUdjUEB2SGiFKCRBYTZAISJRFnaEJmMoRndWBhCDBIJQ\nEXFDYIAieBYnQYIwY2J3hoVRMTYGaDEmgSMxFidoETEjFCgnUYCFQhB4NWhmVAZw\nM0gCEDAWCIcQgXQjgxNkFVZCKCOEiBIFFFA3NBQVZiSCYWRnYXASRISGQTUWAUA4\nIYMhckd2UhiDQYE3RxdAAnEIODYAUUhnMABIERdYFSQkcSYFAyIBASUkFAQEdTJA\nIxZABjhyBjF1Q4UWNEMgFBY4NSdjRxCFhyg0FVIAI1FWVhUlgRBHEGgYKEcIEoEl\ncIRzRWE0Z0g2BzQ2FxUGiEchJ1ZzUBY1d0EQQjd2AwY3KHhDQ1IVAUcIhDgWYIZI\nWFN3BEhTgBciRhNTGGUARoeBMXExNAIwcRYnBRgohUM4gYSARhCIMkMDJVhIgoMS\nR2BRKDFHh2JgGGUyMlIUKCR1ImJFgCY0gFgABgUYBXU2BDRGCHaGiCgTIDIyBFh4\nRmFzUBBCE2FUJWYAY4ZjSAg1BWWFAFQ1hkBjAnMiByEWVIVgN2MXYmBUU2BhYkUh\nOBNEWEBChUSDVgYEZiJ1cjUmNDIGQghgZEUIcUdwZVYjRzgBeHA1gRSGVXYhgmaB\nNVZ3UTgQUSF1NldYc1aDRgdGMVYUdwgQVThTVEJyN2IFUwdgUTZoJhQDVIRzEEdI\nE2YFd2EhESIVMSVFdhRHYAAFBShCEoAXQScWdEdSiGIydUNiZzhmJzY2ZlMTOCYH\nUzcVZxYUiHAxhDgmcWcHZjAFdBSHVhMyhiIyCCcwdgcACGOHRiNlAmAFAyFVVRcW\nFQQhNwIFYUBxNxKGVlQzF4IBEyAYFDF3BzMlUjJyYIMTFDAUFWRDhnWGdABYQRRQ\nh0VTAIgWhnd1FEhng4hlUwMiY2c4hzczM2BzgxRoZRRVRkF1VngWFFEogkEEQAWA\nJ3R3A3IBhmQVaDVGKCJkMlc1GAFwIXQHF4h1RkJVEiJRRQB2ACGEgDFBBDEIWBEx\nVQBBRoFjMzKEKCZYcnRWYVh1M0N4GEMmRIInExYFNUMgExZRQ1h4h3NwdGYEJDJR\nECiCYjQ0Z2ZGIGIwZCZGAFYjaEIzVFIQGEYUBHOBcTJiQSdCF3dCUQEBhgJBRyZU\nJlZxMHKHYHh2E0NwCIdCM3gHBjFWYhJoghJIBCgHI1hWJTRiF2eBcRBRNgISBYZx\nYzYTdoM4YGJWVBBYFzWBAUOHcVaAFERQEWEHExYyZIN4BjhEVQFIgyRAcGY3hiRI\nQkiDckYRgRQQISUQFDR0VxZyZ0hiIgQhOIhgiGdnIlaEJgQARjgxgWBzAgJ2FCAz\nNmgwVlGGdUcxYhZjVCQXAkGIMoJAJwFFBWMGhzExGCA1ZzdIRhMwQiaGN4AlMzNW\nRyFAA3UzYCBSNXOBMUEgRUY0E2wwl7ncBzQaQCHLGi4fo4iNcjppgeVmwIkz3lQc\nB1+enw6xro9Jj41TDjetf9GWcQeGt7rWjs2Q4b1R1IzuRhVgw7PuvtM1PzoP1Wfj\nsT1ugBTv5FzYo1zBx6L1hAYrB1ZR8EY/0qp3JhMeMDNry3kxoWxBk6NRXCl550nV\nDjxIXzzQYBOtvEUdRjX0jKFRtp5r+usf5BY+HjkFPlCxUNZ9U1EuWNZenAG47Q1a\nxL6aiyTUOsmyzXmIRXA3lQVurP1GqH5beYWgt6g+veH9MZm7HqC2iAqrQvTWrfQg\nVh9h6K2VgK7rA7/SUHJS++3l3YqRV+0CL05OSa3+55ZheCQyinGcHqOR4DiaO4tl\nXWlYis6KU7ZkQPwEejPibzrK6OvCBHOYzBmZXu6Q3h57TzCAZoS7Uinm1VHVFqIw\neid4VR9QHv14bj2pj8lz+bSEeP3/quUci+TF9A/CNzrTdv7eYxlS1EGd40PQMA6F\np/ZHenXBp9vp8xCFPO6N4BSpLTm4HATPv0IfSJvalmj8YGMx9baCkuv1zInD/nij\nXjAOpuxXuLo4Odnsyh8nG3ApojSwPew6Nw0/gIkaaBAEHatk36bif14ZfpjdtMSu\nZqqRe28YAX5Cc+CGgwmiMVp1wcfnsREStQljA51Wgh9BMDj864vIxDRwoDvnGUP0\n2us2kCc1YWOYO0fhXnQwLv0SfhMSueXSWI+TtavZ7XEpoxLR59KfQXNr54lD2LVi\nSAIfnugQFY6QWQJy9tqj/EQVRVAz7DtsKYhuaXXXUob1WjRpW1GA0Haz+fflunto\nPVI8jfubex+6clxGXhc8wef3P6mZI//C4qdhU1DL+Lfa+nUvzq2RbsrpZh6wB0RU\na608XykbdkVPR56khUm+a+p4jMQrp2YCmiPj68CvZz49voij9v4sFhUPQ8NuqoRy\nVYRGSSiAccpoDocgn4mcScbj5WgxgDHxhYt2N2FeO37//2AiXNzOhZVSpjNe8OIs\nF5msuuf6lYDFQj8yy5wYkR9VLUMajV54E0vdo1ns3MCZzGUuibHRlkPrAOXMsHrY\n80le9gLR6QUtfT/2C3PPT6v6psdI86FvQbjly24skPaG9Vm0HGOc3ImuQu5m6CbQ\n37Nb8uIMSRG7QBxhVAXAwxXs6KiWZ8TxyS4zn7INRNyBHm1cgZPSxxXfPZIwosjv\nG0cMqD/CCtxriy0HkJjwtCbUYLc0nU+nMEuMCylWvf6w7hw0SkB/Sa9XvPTiMr3m\nB3qxGr69du5HKLFap9HhlYzgOOuPQrzQxAkIIQ2bCxsIPmTuDXJPvCBB84/I5RyL\ndG7j3LsOg4JGjp0+1wQE7+dynxIFru/DCfNSl5En0ON/Pmu4rteTd3X78Wovr6cV\n8bTp+AQ4ZuSk4bT0S9OtC3hAM8WUjQDZplmJkB8tzo6T5fRU9YX0MFAjUAh7MYAe\na6+Up3mxWmYeo+c4msn7aRfvi4lplMoSKHs+rMgN93ExN/M+IUgTUsjlVQselOzV\nSKlUIQ5oXI+f/Sdtt8PKU/ltSFrAvNwowbarIOjClBPeNrNhYgascjzZ6vBbDYkU\nzaWo97QIvsW5Fj63uYNdeKEfGc+Pf6/IkiVBf5kKGUvHjmBXpgmf02FkDRF065pL\nBx8UDeaHpzAcLBMDbUVejokoEtqDZjlkOljhUeiau99YGC3u3vQia8e64Z0IliaH\nFXXH/8l2FR3ZnYWnLBL4YBSmvwOvosB0iQhKaIb05oxzn6xmgotVhTT5IDqE3PX1\nOfpnFIoNe2IPvobu4z1Q5X2YjA8AvgXOsmH71Js4Ihy2DvGXSESVfF6EB9TqpmHC\nYPIhPORi2g7El4iZrbSvAqOoGILx+8HwBTm8rg4zuqCg44J/nEn7vgjA0rzmQ5mm\nuex3OEpi2RosZ4RecwFrbnkDtN8geeiaZGovGjGtLlBwd09VRji0DFy/l8fUqOqi\nNttZxiGLRL8SsOntUzbkNKcH3GnuN2FUOVD/xMiqOl8IvS6EO81CpPq0c8JxHWQ0\new2QsV8EIJLHpjZRNE4wp/3r4Z9U3ziV7ip8N64ScNj0YedJEvRgLM6hracg7Tey\nbOXhJ8FLh1/cGbeGD0tlbwg8YNZeXkA7YYDmlpWw57jZwYoyx7HqgziF0qqLIPIO\ns9CwjtAb26B0trIJHjkpv0EQHtRsOJuaQIXDcj/A8QVSb9F58cVALYb6NVCADdl5\nfytsoVJst8UQRT+AL5i61ZIVFG9URvoDFCJOYfp5WMF26lb6R0OVw0fuo5XHAcql\nT+gPyx5SaU8Klo/2k5jIm4+JQ74/d4srfcqnVPX/5ueIxtvJx+2q+MuhcOPelwmx\nBjPNvzLRcNFQU8/6meFFFVclBfIPDzOspxTOKu6DvcrkMLFiX1Vl40x/FpVMdRFj\nM5DmJR7NoFhoOguGin1cOdpvUmPxGEzKEJfrQqQ5CX4Kj4lHIFjHeYR1nLTagAyA\nrGv029l5af0CcPmQgl4NlTWh5eRtsFs16YDRkz+1xdQwJnpU9Qs91f6ckScGRHaM\npbpJPoCGPT+kNvHbWrziupkaFYRTy3kHlhkZ7aqqq5phtDVk89LmS355V46t6CoL\nclkAwCWPBqUtJ4Dd0G1Qo6v/3wv63GkrezzxMjvINrJ6rVNqQBgLN5fiHzxYNRjD\nUB9BRLJq7updAnEFSNLqifwDwIHD75EtQEOfWoGBE/beMU4vecnzh7Q3aM3YE7zJ\nsZdtSoLzIycXZczICi8kNRZ/yXUS/mswUaUTNwANWGvYpXXsGRjdg8rCG7bMdBzX\nop9qNMFoxbZjg1NnEvlY33gMgHi0hTVeVd3WvFLrOSnV16dIb6wvgIjW90L/dqXx\niKHKlXtaq01N1vpFBQnUhjL+ZvKh2rQpQpyVB4HBdQeSWC16/tYA8EPUZsISZAM2\nnYdbxHlIooPFz/Ali+g0B1JD0wFs/GljQloKVmBG1otF0FMBRvFlLUflcI4VSsDk\nodpZfBwFPq3K3qN6SAgtpKRzaJH7YDZn6XYIcekoAHP0rsqUH34eeHJ3Rv2U2ml0\nlzi+Ydsv+/REFoiLYNL8Gqa6WpVcZ1qCUse6ORnHCWd2Vxf4d8YDvcLwPwEqcB6u\newhC3Gme5ydV4hwTv9SzHOJ2ohTI9J4FpdEmGxOuB9HROQ3c8qPm6PDh5fXwOItz\nqaD8y6RLZUaPMXgwbAI/Gr5EFLAGp6CXfLrKE9yD3yLAop4DZ6GPPoHqOc+hKkgY\nedxUwijnQ25mtgrrJzvUWOpO0hi+CNdcMQMXXU2phyibN8h/JoejzIm9HXk2EvV9\nqX4cmZjkE9fKw15cRjvQt1K1\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/p256.pem",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49\nAwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt\nCeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/rsa-1.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIJJwIBAAKCAgEArIEJUYZrXhMfUXXdl2gLcXrRB4ciWNEeXt5UVLG0nPhygZwJ\nxis8tOrjXOJEpUXUsfgF35pQiJLD4T9/Vp3zLFtMOOQjOR3AxjIelbH9KPyGFEr9\nTcPtsJ24zhcG7RbwOGXR4iIcDaTx+bCLSAd7BjG3XHQtyeepGGRZkGyGUvXjPorH\nXP+dQjQnMd09wv0GMZSqQ06PedUUKQ4PJRfMCP+mwjFP+rB3NZuThF0CsNmpoixg\nGdoQ591Yrf5rf2Bs848JrYdqJlKlBL6rTFf2glHiC+mE5YRny7RZtv/qIkyUNotV\nce1cE0GFrRmCpw9bqulDDcgKjFkhihTg4Voq0UYdJ6Alg7Ur4JerKTfyCaRGF27V\nfh/g2A2/6Vu8xKYYwTAwLn+Tvkx9OTVZ1t15wM7Ma8hHowNoO0g/lWkeltgHLMji\nrmeuIYQ20BQmdx2RRgWKl57D0wO/N0HIR+Bm4vcBoNPgMlk9g5WHA6idHR8TLxOr\ndMMmTiWfefB0/FzGXBv7DuuzHN3+urdCvG1QIMFQ06kHXhr4rC28KbWIxg+PJGM8\noGNEGtGWAOvi4Ov+BVsIdbD5Sfyb4nY3L9qqPl6TxRxMWTKsYCYx11jC8civCzOu\nyL1z+wgIICJ6iGzrfYf6C2BiNV3BC1YCtp2XsG+AooIxCwjL2CP/54MuRnUCAwEA\nAQKCAgAP4+8M0HoRd2d6JIZeDRqIwIyCygLy9Yh7qrVP+/KsRwKdR9dqps73x29c\nPgeexdj67+Lynw9uFT7v/95mBzTAUESsNO+9sizw1OsWVQgB/4kGU4YT5Ml/bHf6\nnApqSqOkPlTgJM46v4f+vTGHWBEQGAJRBO62250q/wt1D1osSDQ/rZ8BxRYiZBV8\nNWocDRzF8nDgtFrpGSS7R21DuHZ2Gb6twscgS6MfkA49sieuTM6gfr/3gavu/+fM\nV1Rlrmc65GE61++CSjijQEEdTjkJ9isBd+hjEBhTnnBpOBfEQxOgFqOvU/MYXv/G\nW0Q6yWJjUwt3OIcoOImrY5L3j0vERneA1Alweqsbws3fXXMjA+jhLxlJqjPvSAKc\nPOi7xu7QCJjSSLAzHSDPdmGmfzlrbdWS1h0mrC5YZYOyToLajfnmAlXNNrytnePg\nJV9/1136ZFrJyEi1JVN3kyrC+1iVd1E+lWK0U1UQ6/25tJvKFc1I+xToaUbK10UN\nycXib7p2Zsc/+ZMlPRgCxWmpIHmKhnwbO7vtRunnnc6wzhvlQQNHWlIvkyQukV50\n6k/bzWw0M6A98B4oCICIcxcpS3njDlHyL7NlkCD+/OfZp6X3RZF/m4grmA2doebz\nglsaNMyGHFrpHkHq19Y63Y4jtBdW/XuBv06Cnr4r3BXdjEzzwQKCAQEA5bj737Nk\nZLA0UgzVVvY67MTserTOECIt4i37nULjRQwsSFiz0AWFOBwUCBJ5N2qDEelbf0Fa\nt4VzrphryEgzLz/95ZXi+oxw1liqCHi8iHeU2wSclDtx2jKv2q7bFvFSaH4CKC4N\nzBJNfP92kdXuAjXkbK/jWwr64fLNh/2KFWUAmrYmtGfnOjjyL+yZhPxBatztE58q\n/T61pkvP9NiLfrr7Xq8fnzrwqGERhXKueyoK6ig9ZJPZ2VTykMUUvNYJJ7OYQZru\nEYA3zkuEZifqmjgF57Bgg7dkkIh285TzH3CNf3MCMTmjlWVyHjlyeSPYgISB9Mys\nVKKQth+SvYcChQKCAQEAwDyCcolA7+bQBfECs6GXi7RYy2YSlx562S5vhjSlY9Ko\nWiwVJWviF7uSBdZRnGUKoPv4K4LV34o2lJpSSTi5Xgp7FH986VdGePe3p4hcXSIZ\nNtsKImLVLnEjrmkZExfQl7p0MkcU/LheCf/eEZVp0Z84O54WCs6GRm9wHYIUyrag\n9FREqqxTRVNhQQ2EDVGq1slREdwB+aygE76axK/qosk0RaoLzGZiMn4Sb8bpJxXO\nmee+ftq5bayVltfR0DhC8eHkcPPFeQMll1g+ML7HbINwHTr01ONm3cFUO4zOLBOO\nws/+vtNfiv6S/lO1RQSRoiApbENBLdSc3V8Cy70PMQKCAQBOcZN4uP5gL5c+KWm0\nT1KhxUDnSdRPyAwY/xC7i7qlullovvlv4GK0XUot03kXBkUJmcEHvF5o6qYtCZlM\ng/MOgHCHtF4Upl5lo1M0n13pz8PB4lpBd+cR1lscdrcTp4Y3bkf4RnmppNpXA7kO\nZZnnoVWGE620ShSPkWTDuj0rvxisu+SNmClqRUXWPZnSwnzoK9a86443efF3fs3d\nUxCXTuxFUdGfgvXo2XStOBMCtcGSYflM3fv27b4C13mUXhY0O2yTgn8m9LyZsknc\nxGalENpbWmwqrjYl8KOF2+gFZV68FZ67Bm6otkJ4ta80VJw6joT9/eIe6IA34KIw\nG+ktAoIBAFRuPxzvC4ZSaasyX21l25mQbC9pdWDKEkqxCmp3VOyy6R4xnlgBOhwS\nVeAacV2vQyvRfv4dSLIVkkNSRDHEqCWVlNk75TDXFCytIAyE54xAHbLqIVlY7yim\nqHVB07F/FC6PxdkPPziAAU2DA5XVedSHibslg6jbbD4jU6qiJ1+hNrAZEs+jQC+C\nn4Ri20y+Qbp0URb2+icemnARlwgr+3HjzQGL3gK4NQjYNmDBjEWOXl9aWWB90FNL\nKahGwfAhxcVW4W56opCzwR7nsujV4eDXGba83itidRuQfd5pyWOyc1E86TYGwD/b\n79OkEElv6Ea8uXTDVS075GmWATRapQECggEAd9ZAbyT+KouTfi2e6yLOosxSZfns\neF06QAJi5n9GOtdfK5fqdmHJqJI7wbubCnd0oxPeL71lRjrOAMXufaQRdZtfXSMn\nB1TljteNrh1en5xF451rCPR/Y6tNKBvIKnhy1waO27/vA+ovXrm17iR9rRuGZ29i\nIurlKA6z/96UdrSdpqITTCyTjSOBYg34f49ueGjlpL4+8HJq2wor4Cb1Sbv8ErqA\nbsQ/Jz+KIGUiuFCfNa6d6McPRXIrGgzpprXgfimkV3nj49QyrnuCF/Pc4psGgIaN\nl3EiGXzRt/55K7DQVadtbcjo9zREac8QnDD6dS/gOfJ82L7frQfMpNWgQA==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/rsa-2.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEA1HUbx825tG7+/ulC5DpDogzXqM2/KmeCwGXZY4XjiWa+Zj7b\nECkZwQh7zxFUsPixGqQKJSyFwCogdaPzYTRNtqKKaw/IWS0um1PTn4C4/9atbIsf\nHVKu/fWg4VrZL+ixFIZxa8Z6pvTB2omMcx+uEzbXPsO01i1pHf7MaWBxUDGFyC9P\nlASJBfFZAf2Ar1H99OTS4SP+gxM9Kk5tcc22r8uFiqqbhJmQNSDApdHvT1zSZxAc\nT1BFEZqfmR0B0UegPyJc/9hW0dYpB9JjR29UaZRSta3LUMpqltoOF5bzaKVgMuBm\nQy79xJ71LjGp8bKhgRaWXyPsDzAC0MQlOW6En0v8LK8fntivJEvw9PNOMcZ8oMTn\nno0NeVt32HiQJW8LIVo7dOLVFtguSBMWUVe8mdKbuIIULD6JlSYke9Ob6andUhzO\nU79m/aRWs2yjD6o5QAktjFBARdPgcpTdWfppc8xpJUkQgRmVhINoIMT9W6Wl898E\nP4aPx6mRV/k05ellN3zRgd9tx5dyNuj3RBaNmR47cAVvGYRQgtH9bQYs6jtf0oer\nA5yIYEKspNRlZZJKKrQdLflQFOEwjQJyZnTk7Mp0y21wOuEGgZBexew55/hUJDC2\nmQ8CqjV4ki/Mm3z6Cw3jXIMNBJkH7oveBGSX0S9bF8A/73oOCU3W/LkORxECAwEA\nAQKCAgBLK7RMmYmfQbaPUtEMF2FesNSNMV72DfHBSUgFYpYDQ4sSeiLgMOqf1fSY\nazVf+F4RYwED7iDUwRMDDKNMPUlR2WjIQKlOhCH9a0dxJAZQ3xA1W3QC2AJ6cLIf\nihlWTip5bKgszekPsYH1ZL2A7jCVM84ssuoE7cRHjKOelTUCfsMq9TJe2MvyglZP\n0fX6EjSctWm3pxiiH+iAU4d9wJ9my8fQLFUiMYNIiPIguYrGtbzsIlMh7PDDLcZS\nUmUWOxWDwRDOpSjyzadu0Q23dLiVMpmhFoDdcQENptFdn1c4K2tCFQuZscKwEt4F\nHiVXEzD5j5hcyUT4irA0VXImQ+hAH3oSDmn7wyHvyOg0bDZpUZXEHXb83Vvo54/d\nFb4AOUva1dwhjci8CTEMxCENMy/CLilRv46AeHbOX8KMPM7BnRSJPptvTTh/qB9C\nHI5hxfkO+EOYnu0kUlxhJfrqG86H4IS+zA8HWiSEGxQteMjUQfgJoBzJ94YChpzo\nePpKSpjxxl1PNNWKxWM3yUvlKmI2lNl6YNC8JpF2wVg4VvYkG7iVjleeRg21ay89\nNCVMF98n3MI5jdzfDKACnuYxg7sw+gjMy8PSoFvQ5pvHuBBOpa8tho6vk7bLJixT\nQY5uXMNQaO6OwpkBssKpnuXhIJzDhO48nSjJ5nUEuadPH1nGwQKCAQEA7twrUIMi\nVqze/X6VyfEBnX+n3ZyQHLGqUv/ww1ZOOHmSW5ceC4GxHa8EPDjoh9NEjYffwGq9\nbfQh9Gntjk5gFipT/SfPrIhbPt59HthUqVvOGgSErCmn0vhsa0+ROpVi4K2WHS7O\n7SEwnoCWd6p1omon2olVY0ODlMH4neCx/ZuKV8SRMREubABlL8/MLp37AkgKarTY\ntewd0lpaZMvsjOhr1zVCGUUBxy87Fc7OKAcoQY8//0r8VMH7Jlga7F2PKVPzqRKf\ntjeW5jMAuRxTqtEdIeclJZwvUMxvb23BbBE+mtvKpXv69TB3DK8T1YIkhW2CidZW\nlad4MESC+QFNbQKCAQEA47PtULM/0ZFdE+PDDHOa2kJ2arm94sVIqF2168ZLXR69\nNkvCWfjkUPDeejINCx7XQgk0d/+5BCvrJpcM7lE4XfnYVNtPpct1el6eTfaOcPU8\nwAMsnq5n9Mxt02U+XRPtEqGk+lt0KLPDDSG88Z7jPmfftigLyPH6i/ZJyRUETlGk\nrGnWSx/LFUxQU5aBa2jUCjKOKa+OOk2jGg50A5Cmk26v9sA/ksOHisMjfdIpZc9P\nr4R0IteDDD5awlkWTF++5u1GpgU2yav4uan0wzY8OWYFzVyceA6+wffEcoplLm82\nCPd/qJOB5HHkjoM+CJgfumFxlNtdowKvKNUxpoQNtQKCAQEAh3ugofFPp+Q0M4r6\ngWnPZbuDxsLIR05K8vszYEjy4zup1YO4ygQNJ24fM91/n5Mo/jJEqwqgWd6w58ax\ntRclj00BCMXtGMrbHqTqSXWhR9LH66AGdPTHuXWpYZDnKliTlic/z1u+iWhbAHyl\nXEj2omIeKunc4gnod5cyYrKRouz3omLfi/pX33C19FGkWgjH2HpuViowBbhhDfCr\n9yJoEWC/0njl/hlTMdzLYcpEyxWMMuuC/FZXG+hPgWdWFh3XVzTEL3Fd3+hWEkp5\nrYWwu2ITaSiHvHaDrAvZZVXW8WoynXnvzr+tECgmTq57zI4eEwSTl4VY5VfxZ0dl\nFsIzXQKCAQBC07GYd6MJPGJWzgeWhe8yk0Lxu6WRAll6oFYd5kqD/9uELePSSAup\n/actsbbGRrziMpVlinWgVctjvf0bjFbArezhqqPLgtTtnwtS0kOnvzGfIM9dms4D\nuGObISGWa5yuVSZ4G5MRxwA9wGMVfo4u6Iltin868FmZ7iRlkXd8DNYJi95KmgAe\nNhF1FrzQ6ykf/QpgDZfuYI63vPorea6JonieMHn39s622OJ3sNBZguheGL+E4j8h\nvsMgOskijQ8X8xdC7lDQC1qqEsk06ZvvNJQLW1zIl3tArhjHjPp5EEaJhym+Ldx3\nUT3E3Zu9JfhZ2PNevqrShp0lnLw/pI3pAoIBAAUMz5Lj6V9ftsl1pTa8WDFeBJW0\nWa5AT1BZg/ip2uq2NLPnA5JWcD+v682fRSvIj1pU0DRi6VsXlzhs+1q3+sgqiXGz\nu2ArFylh8TvC1gXUctXKZz/M3Rqr6aSNoejUGLmvHre+ja/k6Zwmu6ePtB7dL50d\n6+xMTYquS4gLbrbSLcEu3iBAAnvRLreXK4KguPxaBdICB7v7epdpAKe3Z7hp/sst\neJj1+6KRdlcmt8fh5MPkBBXa6I/9XGmX5UEo7q4wAxeM9nuFWY3watz/EO9LiO6P\nLmqUSWL65m4cX0VZPvhYEsHppKi1eoWGlHqS4Af5+aIXi2alu2iljQFeA+Q=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/rsa-3.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEAzn+YCcOh7BIRzrb7TEuhQLD545+/Fx/zCYO3l+y/8ogUxMTg\nLG5HrcXlX3JP796ie90/GHIf8/lwczVhP1jk/keYjkwoTYDt477R7KRcJPyGqHRr\nqLp7AnZxtz3JLNboTgO3bAYzlvtsSKU/R3oehBbGHzEWCP2UEYj/Kky0zpcjkhZU\njiErr9ARPq8+dOGqBf+CE2NLKYC1bu8hZe9AddvvN2SvfMN6uhJtEGZO1k8tScwf\nAyvPJ1Po/6z08pzMAgfBUCE95waAVeYJWIOlnNB4eEievzlXdPB9vEt8OOwtWfQX\nV8xyMsoKeAW05s413E0eTYx1aulFXdWwG2mWEBRtNzKF1iBudlg1a3x1zThWi1pY\njW5vROvoWZMCbl9bYQ/LxOCVqDoUl86+NPEGeuESMzm5NvOQA2e0Ty5wphnt9M19\nWcc8neBhb6iCGqYzxWNvUYXZWUv1+/MrPHKyJuv7MSivwtctfp8SacUGxkd6T+u6\nV6ntHf3qtN/5pAmni6nzUTgjC65MS0LEhi/RTzwafkIfifeJH7/LqFtjrursuwua\n+p9lkACck/J5TpzaAfLroFQuepP8qgeq1cpD5Iii56IJ+FPSnkvesHuRUmZIkhtR\nVVsVqMaNPv/Uzc02bOaRXWP4auUY91mDKx/FDmORa9YCDQxMkKke05SWQ90CAwEA\nAQKCAgA0+B/c6VTgxGXS+7cMhB3yBTOkgva2jNh/6Uyv6Of345ZIPyQt4X/7gFbt\nG9qLcjWFxmQH9kZiA+snclrmr/vVijIE1l5EOz1KfUlGBYcpaal1DqALIQKqyA01\nbuDq4pmmYWesiw6yvP2yyMipohav1VOu7p1zYvCXaufhRtneYICcWaQI7VNSfvHd\nfYBs5PIDJd6M8Jx4Ie7obOjJSAzl7qu3LtmhDFev4Ugeu8+fQ6IfWv/dhWBW+zw6\nUXhnv3bJUonw7wX8+/rxjdd54BMcXZF5cU9fR+s6MPJf2ZEc3OBpQaa3O9dTVeZH\nkVctGVpRj2qlg9EewoWro0PQVE5Mjah+mdFhPAHWoGl1xht6xJmg0uHYxMCzbUSz\n7NSS3knR0qieFvsp5ESY72i7DnQsbhbn6mTuYdVtm9bphxifAWCP3jFdft/bjtSF\n4yuPI7Qga+3m0B8QhtbWhEzPVon6NyiY7qfa6qllp0opEbw2hE22uGFFNJo2mpPa\npe9VwARtD0IyfeklE7KrBEwV8NjTaAipZTZODw0w/dt4K3dOiePDl3pPWjmERpVg\nLkw7XSCMtu5X87I1BbfOYbQhOXksPY+W9Asf6ETBeIZ8bD6Iypuk2ssool1lukqv\nyq1Y8gbR9B2x91ftYwXgzqBSvd8PFNsaXWLD3nrai2G1vb81lQKCAQEA6W02eZcN\n7wJfkqNokcuqhc5OKXH14gVIRV+KocG6f3vg88wrCg5J2GqNhBFuwVrafJjRenm6\nC8zWdneeyrl6cztgbaySw7kXnqFdTBiuOT8bhiG5NTPjDQ109EucaTbZU9KUXk6k\nChPlr4G6IPrONpvi/9BvDDZLZkwR6uIg1kFWBy9kZaxFUEIug02hrbkTpPtnEUrO\nr3nG0QL/D0vf+bm4YHIVRMH2O2ZTTWexMw9XlfCe1+WjbJ+PS35QRCRDcRdWHXDb\nHnIFIAajtH5LtaJLgWUYq3B25WkQYtbHmFkm94sp/G4trb8JIJGzVO8cj9t6KeAT\nLG+tk8OqplqsYwKCAQEA4ne81KXx8VNwsKVFqwmiDIoi1q3beNa2hoXdzAMrnYdj\niLxbfCVgrKPav9hdfXPBncHaNlGsd2G5W1a1UsOr128lTdfBsgm1RVPhVMKvo3fl\nyUnWajtAR1q3tVEUhuFlbJ/RHEtxJaGrzudYCPWQiYhydpDgSckbxD8PuElEgFBX\nO91vnWZEjMsxrABWiZNBxmtBUEv+fjUU/9USYzO4sN79UeD1+ZuBxPFwscsRcjLr\nbPgZWOwiywH6UmQ+DJTzeu0wJ6jgPoy/pgEujsbPDz1wNos6NhA/RQv31QeX33/B\n7/F5XKNmbJ2AFb/B+xTaTQPg0pjT5Exm+HrNU5OivwKCAQEAsLLVi9FG4OiBBHXi\nUItFuChljoYPxVqOTMV4Id6OmLZjoOmqouASElsGaTTxDDkEL1FXMUk4Bnq21dLT\nR06EXPpTknISX0qbkJ9CCrqcGAWnhi+9DYMLmvPW1p7t9c9pUESVv5X0IxTQx7yB\n8zkoJLp4aYGUrj/jb7qhzZYDmWy3/JRpgXWYupp+rzJy8xiowDj22mYwczDRyaJl\nBWVAVL+7zHZPl07kYC6jXHLj9mzktkIBXBkfTriyNkmV5R82VkN+Eqc9l5xkOMwN\n3DHGieYjFf47YHuv5RVVLBy91puWHckgrU+SEHYOKLNidybSDivsHArdOMQJN1Pk\nuCznVQKCAQAYY7DQbfa6eLQAMixomSb8lrvdxueGAgmyPyR93jGKS5Rqm2521ket\nEBB07MZUxmyposDvbKhYSwv9TD9G5I/TKcMouP3BQM5m4vu3dygXQMhcfzk6Q5tO\nk/SI8Gx3gjq8EhIhK/bJiLnKFJwkit3AEhPRtRSSnbgB0JDO1gUslHpwlg55MxRa\n3V9CGN84/cTtq4tjLGwCB5F1Y+sRB/byBXHeqY2UDi1Rmnb6jtYYKGe2WpnQO84b\ncuEUknskO75lFLpE6ykLU3koVaQ/+CVAjOtS1He2btWBiCJurNysU0P9pVHeqjJT\nrDqpHPe1JK/F74783zyir5+/Tuph/9pdAoIBAANPdFRQkJVH8K6iuhxQk6vFqiYB\nMUxpIVeLonD0p9TgMdezVNESht/AIutc0+5wabM45XuDWFRTuonvcE8lckv2Ux3a\nAvSsamjuesxw2YmkEtzZouVqDU0+oxppQJiwBG3MiaHX9F5IfnK6YmQ6xPwZ6MXi\n9feq1jR4KOc1ZrHtRMNgjnBWEFWroGe3FHgV7O133hpMSshRFmwcbE0nAaDr82U9\nsl8dclDjEKBxaqjAeNajOr+BU0w0AAwWXL7dt/ctG2QClcj9wqbEfsXnOR10h4AI\nrqkcvQrOLbTwcrOD/6R1rQfQXtEHKf1maThxosootAQZXdf6jxU3oonx3tU=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/openssl/fixtures/pkey/rsa2048.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN\ns9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign\n4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D\nkYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl\nNwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J\nDRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb\nI0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq\nPIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V\nseSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0\nXc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc\nVsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW\nwORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G\n0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj\nXGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb\naqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n\nh2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw\nIvnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k\nIQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb\nv4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId\nU0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr\nvd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS\nCc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC\n9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41\ngBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG\n4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/openssl/test_asn1.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass  OpenSSL::TestASN1 < OpenSSL::TestCase\n  def test_decode_x509_certificate\n    subj = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=TestCA\")\n    key = Fixtures.pkey(\"rsa-1\")\n    now = Time.at(Time.now.to_i) # suppress usec\n    s = 0xdeadbeafdeadbeafdeadbeafdeadbeaf\n    exts = [\n      [\"basicConstraints\",\"CA:TRUE,pathlen:1\",true],\n      [\"keyUsage\",\"keyCertSign, cRLSign\",true],\n      [\"subjectKeyIdentifier\",\"hash\",false],\n    ]\n    dgst = OpenSSL::Digest.new('SHA256')\n    cert = OpenSSL::TestUtils.issue_cert(\n      subj, key, s, exts, nil, nil, digest: dgst, not_before: now, not_after: now+3600)\n\n\n    asn1 = OpenSSL::ASN1.decode(cert)\n    assert_equal(OpenSSL::ASN1::Sequence, asn1.class)\n    assert_equal(3, asn1.value.size)\n    tbs_cert, sig_alg, sig_val = *asn1.value\n\n    assert_equal(OpenSSL::ASN1::Sequence, tbs_cert.class)\n    assert_equal(8, tbs_cert.value.size)\n\n    version = tbs_cert.value[0]\n    assert_equal(:CONTEXT_SPECIFIC, version.tag_class)\n    assert_equal(0, version.tag)\n    assert_equal(1, version.value.size)\n    assert_equal(OpenSSL::ASN1::Integer, version.value[0].class)\n    assert_equal(2, version.value[0].value)\n\n    serial = tbs_cert.value[1]\n    assert_equal(OpenSSL::ASN1::Integer, serial.class)\n    assert_equal(0xdeadbeafdeadbeafdeadbeafdeadbeaf, serial.value)\n\n    sig = tbs_cert.value[2]\n    assert_equal(OpenSSL::ASN1::Sequence, sig.class)\n    assert_equal(2, sig.value.size)\n    assert_equal(OpenSSL::ASN1::ObjectId, sig.value[0].class)\n    assert_equal(\"1.2.840.113549.1.1.11\", sig.value[0].oid)\n    assert_equal(OpenSSL::ASN1::Null, sig.value[1].class)\n\n    dn = tbs_cert.value[3] # issuer\n    assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash)\n    assert_equal(OpenSSL::ASN1::Sequence, dn.class)\n    assert_equal(3, dn.value.size)\n    assert_equal(OpenSSL::ASN1::Set, dn.value[0].class)\n    assert_equal(OpenSSL::ASN1::Set, dn.value[1].class)\n    assert_equal(OpenSSL::ASN1::Set, dn.value[2].class)\n    assert_equal(1, dn.value[0].value.size)\n    assert_equal(1, dn.value[1].value.size)\n    assert_equal(1, dn.value[2].value.size)\n    assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class)\n    assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class)\n    assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class)\n    assert_equal(2, dn.value[0].value[0].value.size)\n    assert_equal(2, dn.value[1].value[0].value.size)\n    assert_equal(2, dn.value[2].value[0].value.size)\n    oid, value = *dn.value[0].value[0].value\n    assert_equal(OpenSSL::ASN1::ObjectId, oid.class)\n    assert_equal(\"0.9.2342.19200300.100.1.25\", oid.oid)\n    assert_equal(OpenSSL::ASN1::IA5String, value.class)\n    assert_equal(\"org\", value.value)\n    oid, value = *dn.value[1].value[0].value\n    assert_equal(OpenSSL::ASN1::ObjectId, oid.class)\n    assert_equal(\"0.9.2342.19200300.100.1.25\", oid.oid)\n    assert_equal(OpenSSL::ASN1::IA5String, value.class)\n    assert_equal(\"ruby-lang\", value.value)\n    oid, value = *dn.value[2].value[0].value\n    assert_equal(OpenSSL::ASN1::ObjectId, oid.class)\n    assert_equal(\"2.5.4.3\", oid.oid)\n    assert_equal(OpenSSL::ASN1::UTF8String, value.class)\n    assert_equal(\"TestCA\", value.value)\n\n    validity = tbs_cert.value[4]\n    assert_equal(OpenSSL::ASN1::Sequence, validity.class)\n    assert_equal(2, validity.value.size)\n    assert_equal(OpenSSL::ASN1::UTCTime, validity.value[0].class)\n    assert_equal(now, validity.value[0].value)\n    assert_equal(OpenSSL::ASN1::UTCTime, validity.value[1].class)\n    assert_equal(now+3600, validity.value[1].value)\n\n    dn = tbs_cert.value[5] # subject\n    assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash)\n    assert_equal(OpenSSL::ASN1::Sequence, dn.class)\n    assert_equal(3, dn.value.size)\n    assert_equal(OpenSSL::ASN1::Set, dn.value[0].class)\n    assert_equal(OpenSSL::ASN1::Set, dn.value[1].class)\n    assert_equal(OpenSSL::ASN1::Set, dn.value[2].class)\n    assert_equal(1, dn.value[0].value.size)\n    assert_equal(1, dn.value[1].value.size)\n    assert_equal(1, dn.value[2].value.size)\n    assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class)\n    assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class)\n    assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class)\n    assert_equal(2, dn.value[0].value[0].value.size)\n    assert_equal(2, dn.value[1].value[0].value.size)\n    assert_equal(2, dn.value[2].value[0].value.size)\n    oid, value = *dn.value[0].value[0].value\n    assert_equal(OpenSSL::ASN1::ObjectId, oid.class)\n    assert_equal(\"0.9.2342.19200300.100.1.25\", oid.oid)\n    assert_equal(OpenSSL::ASN1::IA5String, value.class)\n    assert_equal(\"org\", value.value)\n    oid, value = *dn.value[1].value[0].value\n    assert_equal(OpenSSL::ASN1::ObjectId, oid.class)\n    assert_equal(\"0.9.2342.19200300.100.1.25\", oid.oid)\n    assert_equal(OpenSSL::ASN1::IA5String, value.class)\n    assert_equal(\"ruby-lang\", value.value)\n    oid, value = *dn.value[2].value[0].value\n    assert_equal(OpenSSL::ASN1::ObjectId, oid.class)\n    assert_equal(\"2.5.4.3\", oid.oid)\n    assert_equal(OpenSSL::ASN1::UTF8String, value.class)\n    assert_equal(\"TestCA\", value.value)\n\n    pkey = tbs_cert.value[6]\n    assert_equal(OpenSSL::ASN1::Sequence, pkey.class)\n    assert_equal(2, pkey.value.size)\n    assert_equal(OpenSSL::ASN1::Sequence, pkey.value[0].class)\n    assert_equal(2, pkey.value[0].value.size)\n    assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class)\n    assert_equal(\"1.2.840.113549.1.1.1\", pkey.value[0].value[0].oid)\n    assert_equal(OpenSSL::ASN1::BitString, pkey.value[1].class)\n    assert_equal(0, pkey.value[1].unused_bits)\n    spkey = OpenSSL::ASN1.decode(pkey.value[1].value)\n    assert_equal(OpenSSL::ASN1::Sequence, spkey.class)\n    assert_equal(2, spkey.value.size)\n    assert_equal(OpenSSL::ASN1::Integer, spkey.value[0].class)\n    assert_equal(cert.public_key.n, spkey.value[0].value)\n    assert_equal(OpenSSL::ASN1::Integer, spkey.value[1].class)\n    assert_equal(cert.public_key.e, spkey.value[1].value)\n\n    extensions = tbs_cert.value[7]\n    assert_equal(:CONTEXT_SPECIFIC, extensions.tag_class)\n    assert_equal(3, extensions.tag)\n    assert_equal(1, extensions.value.size)\n    assert_equal(OpenSSL::ASN1::Sequence, extensions.value[0].class)\n    assert_equal(3, extensions.value[0].value.size)\n\n    ext = extensions.value[0].value[0]  # basicConstraints\n    assert_equal(OpenSSL::ASN1::Sequence, ext.class)\n    assert_equal(3, ext.value.size)\n    assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class)\n    assert_equal(\"2.5.29.19\",  ext.value[0].oid)\n    assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class)\n    assert_equal(true, ext.value[1].value)\n    assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class)\n    extv = OpenSSL::ASN1.decode(ext.value[2].value)\n    assert_equal(OpenSSL::ASN1::Sequence, extv.class)\n    assert_equal(2, extv.value.size)\n    assert_equal(OpenSSL::ASN1::Boolean, extv.value[0].class)\n    assert_equal(true, extv.value[0].value)\n    assert_equal(OpenSSL::ASN1::Integer, extv.value[1].class)\n    assert_equal(1, extv.value[1].value)\n\n    ext = extensions.value[0].value[1]  # keyUsage\n    assert_equal(OpenSSL::ASN1::Sequence, ext.class)\n    assert_equal(3, ext.value.size)\n    assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class)\n    assert_equal(\"2.5.29.15\",  ext.value[0].oid)\n    assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class)\n    assert_equal(true, ext.value[1].value)\n    assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class)\n    extv = OpenSSL::ASN1.decode(ext.value[2].value)\n    assert_equal(OpenSSL::ASN1::BitString, extv.class)\n    str = +\"\\000\"; str[0] = 0b00000110.chr\n    assert_equal(str, extv.value)\n\n    ext = extensions.value[0].value[2]  # subjectKeyIdentifier\n    assert_equal(OpenSSL::ASN1::Sequence, ext.class)\n    assert_equal(2, ext.value.size)\n    assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class)\n    assert_equal(\"2.5.29.14\",  ext.value[0].oid)\n    assert_equal(OpenSSL::ASN1::OctetString, ext.value[1].class)\n    extv = OpenSSL::ASN1.decode(ext.value[1].value)\n    assert_equal(OpenSSL::ASN1::OctetString, extv.class)\n    sha1 = OpenSSL::Digest.new('SHA1')\n    sha1.update(pkey.value[1].value)\n    assert_equal(sha1.digest, extv.value)\n\n    assert_equal(OpenSSL::ASN1::Sequence, sig_alg.class)\n    assert_equal(2, sig_alg.value.size)\n    assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class)\n    assert_equal(\"1.2.840.113549.1.1.1\", pkey.value[0].value[0].oid)\n    assert_equal(OpenSSL::ASN1::Null, pkey.value[0].value[1].class)\n\n    assert_equal(OpenSSL::ASN1::BitString, sig_val.class)\n    cululated_sig = key.sign(OpenSSL::Digest.new('SHA256'), tbs_cert.to_der)\n    assert_equal(cululated_sig, sig_val.value)\n  end\n\n  def test_decode_all\n    raw = B(%w{ 02 01 01 02 01 02 02 01 03 })\n    ary = OpenSSL::ASN1.decode_all(raw)\n    assert_equal(3, ary.size)\n    ary.each_with_index do |asn1, i|\n      assert_universal(OpenSSL::ASN1::INTEGER, asn1)\n      assert_equal(i + 1, asn1.value)\n    end\n  end\n\n  def test_object_id_register\n    oid = \"1.2.34.56789\"\n    pend \"OID 1.2.34.56789 is already registered\" if OpenSSL::ASN1::ObjectId(oid).sn\n    assert_equal true, OpenSSL::ASN1::ObjectId.register(oid, \"ossl-test-sn\", \"ossl-test-ln\")\n    obj = OpenSSL::ASN1::ObjectId(oid)\n    assert_equal oid, obj.oid\n    assert_equal \"ossl-test-sn\", obj.sn\n    assert_equal \"ossl-test-ln\", obj.ln\n    obj = encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId(\"ossl-test-ln\")\n    assert_equal \"ossl-test-sn\", obj.value\n  end\n\n  def test_end_of_content\n    encode_decode_test B(%w{ 00 00 }), OpenSSL::ASN1::EndOfContent.new\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 00 01 00 }))\n    }\n  end\n\n  def test_boolean\n    encode_decode_test B(%w{ 01 01 00 }), OpenSSL::ASN1::Boolean.new(false)\n    encode_decode_test B(%w{ 01 01 FF }), OpenSSL::ASN1::Boolean.new(true)\n    decode_test B(%w{ 01 01 01 }), OpenSSL::ASN1::Boolean.new(true)\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 01 02 00 00 }))\n    }\n  end\n\n  def test_integer\n    encode_decode_test B(%w{ 02 01 00 }), OpenSSL::ASN1::Integer.new(0)\n    encode_decode_test B(%w{ 02 01 48 }), OpenSSL::ASN1::Integer.new(72)\n    encode_decode_test B(%w{ 02 02 00 80 }), OpenSSL::ASN1::Integer.new(128)\n    encode_decode_test B(%w{ 02 01 81 }), OpenSSL::ASN1::Integer.new(-127)\n    encode_decode_test B(%w{ 02 01 80 }), OpenSSL::ASN1::Integer.new(-128)\n    encode_decode_test B(%w{ 02 01 FF }), OpenSSL::ASN1::Integer.new(-1)\n    encode_decode_test B(%w{ 02 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(2 ** 64)\n    encode_decode_test B(%w{ 02 09 FF 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(-(2 ** 64))\n    # FIXME: OpenSSL < 1.1.0 does not fail\n    # assert_raise(OpenSSL::ASN1::ASN1Error) {\n    #   OpenSSL::ASN1.decode(B(%w{ 02 02 00 7F }))\n    # }\n    # assert_raise(OpenSSL::ASN1::ASN1Error) {\n    #   OpenSSL::ASN1.decode(B(%w{ 02 02 FF 80 }))\n    # }\n  end\n\n  def test_enumerated\n    encode_decode_test B(%w{ 0A 01 00 }), OpenSSL::ASN1::Enumerated.new(0)\n    encode_decode_test B(%w{ 0A 01 48 }), OpenSSL::ASN1::Enumerated.new(72)\n    encode_decode_test B(%w{ 0A 02 00 80 }), OpenSSL::ASN1::Enumerated.new(128)\n    encode_decode_test B(%w{ 0A 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Enumerated.new(2 ** 64)\n  end\n\n  def test_bitstring\n    encode_decode_test B(%w{ 03 01 00 }), OpenSSL::ASN1::BitString.new(B(%w{}))\n    encode_decode_test B(%w{ 03 02 00 01 }), OpenSSL::ASN1::BitString.new(B(%w{ 01 }))\n    obj = OpenSSL::ASN1::BitString.new(B(%w{ F0 }))\n    obj.unused_bits = 4\n    encode_decode_test B(%w{ 03 02 04 F0 }), obj\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 03 00 }))\n    }\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 03 03 08 FF 00 }))\n    }\n    # OpenSSL does not seem to prohibit this, though X.690 8.6.2.3 (15/08) does\n    # assert_raise(OpenSSL::ASN1::ASN1Error) {\n    #   OpenSSL::ASN1.decode(B(%w{ 03 01 04 }))\n    # }\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      obj = OpenSSL::ASN1::BitString.new(B(%w{ FF FF }))\n      obj.unused_bits = 8\n      obj.to_der\n    }\n  end\n\n  def test_string_basic\n    test = -> (tag, klass) {\n      encode_decode_test tag.chr + B(%w{ 00 }), klass.new(B(%w{}))\n      encode_decode_test tag.chr + B(%w{ 02 00 01 }), klass.new(B(%w{ 00 01 }))\n    }\n    test.(4, OpenSSL::ASN1::OctetString)\n    test.(12, OpenSSL::ASN1::UTF8String)\n    test.(18, OpenSSL::ASN1::NumericString)\n    test.(19, OpenSSL::ASN1::PrintableString)\n    test.(20, OpenSSL::ASN1::T61String)\n    test.(21, OpenSSL::ASN1::VideotexString)\n    test.(22, OpenSSL::ASN1::IA5String)\n    test.(25, OpenSSL::ASN1::GraphicString)\n    test.(26, OpenSSL::ASN1::ISO64String)\n    test.(27, OpenSSL::ASN1::GeneralString)\n    test.(28, OpenSSL::ASN1::UniversalString)\n    test.(30, OpenSSL::ASN1::BMPString)\n  end\n\n  def test_null\n    encode_decode_test B(%w{ 05 00 }), OpenSSL::ASN1::Null.new(nil)\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 05 01 00 }))\n    }\n  end\n\n  def test_object_identifier\n    obj = encode_decode_test B(%w{ 06 01 00 }), OpenSSL::ASN1::ObjectId.new(\"0.0\".b)\n    assert_equal \"0.0\", obj.oid\n    assert_nil obj.sn\n    assert_nil obj.ln\n    assert_equal obj.oid, obj.value\n    encode_decode_test B(%w{ 06 01 28 }), OpenSSL::ASN1::ObjectId.new(\"1.0\".b)\n    encode_decode_test B(%w{ 06 03 88 37 03 }), OpenSSL::ASN1::ObjectId.new(\"2.999.3\".b)\n    encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId.new(\"1.2.34.56789\".b)\n    obj = encode_decode_test B(%w{ 06 09 60 86 48 01 65 03 04 02 01 }), OpenSSL::ASN1::ObjectId.new(\"sha256\")\n    assert_equal \"2.16.840.1.101.3.4.2.1\", obj.oid\n    assert_equal \"SHA256\", obj.sn\n    assert_equal \"sha256\", obj.ln\n    assert_equal obj.sn, obj.value\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 06 00 }))\n    }\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 06 01 80 }))\n    }\n    assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new(\"3.0\".b).to_der }\n    assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new(\"0.40\".b).to_der }\n\n    oid = (0...100).to_a.join(\".\").b\n    obj = OpenSSL::ASN1::ObjectId.new(oid)\n    assert_equal oid, obj.oid\n  end\n\n  def test_object_identifier_equality\n    aki = [\n      OpenSSL::ASN1::ObjectId.new(\"authorityKeyIdentifier\"),\n      OpenSSL::ASN1::ObjectId.new(\"X509v3 Authority Key Identifier\"),\n      OpenSSL::ASN1::ObjectId.new(\"2.5.29.35\")\n    ]\n\n    ski = [\n      OpenSSL::ASN1::ObjectId.new(\"subjectKeyIdentifier\"),\n      OpenSSL::ASN1::ObjectId.new(\"X509v3 Subject Key Identifier\"),\n      OpenSSL::ASN1::ObjectId.new(\"2.5.29.14\")\n    ]\n\n    aki.each do |a|\n      aki.each do |b|\n        assert_equal true, a == b\n      end\n\n      ski.each do |b|\n        assert_equal false, a == b\n      end\n    end\n\n    obj1 = OpenSSL::ASN1::ObjectId.new(\"1.2.34.56789.10\")\n    obj2 = OpenSSL::ASN1::ObjectId.new(\"1.2.34.56789.10\")\n    obj3 = OpenSSL::ASN1::ObjectId.new(\"1.2.34.56789.11\")\n    omit \"OID 1.2.34.56789.10 is registered\" if obj1.sn\n    assert_equal true, obj1 == obj2\n    assert_equal false, obj1 == obj3\n\n    assert_equal false, OpenSSL::ASN1::ObjectId.new(\"authorityKeyIdentifier\") == nil\n  end\n\n  def test_sequence\n    encode_decode_test B(%w{ 30 00 }), OpenSSL::ASN1::Sequence.new([])\n    encode_decode_test B(%w{ 30 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Sequence.new([\n      OpenSSL::ASN1::Null.new(nil),\n      OpenSSL::ASN1::Sequence.new([]),\n      OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))\n    ])\n\n    expected = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))])\n    expected.indefinite_length = true\n    encode_decode_test B(%w{ 30 80 04 01 00 00 00 }), expected\n\n    # OpenSSL::ASN1::EndOfContent can only be at the end\n    obj = OpenSSL::ASN1::Sequence.new([\n      OpenSSL::ASN1::EndOfContent.new,\n      OpenSSL::ASN1::OctetString.new(B(%w{ 00 })),\n      OpenSSL::ASN1::EndOfContent.new,\n    ])\n    obj.indefinite_length = true\n    assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der }\n\n    # The last EOC in value is ignored if indefinite length form is used\n    expected = OpenSSL::ASN1::Sequence.new([\n      OpenSSL::ASN1::OctetString.new(B(%w{ 00 })),\n      OpenSSL::ASN1::EndOfContent.new\n    ])\n    expected.indefinite_length = true\n    encode_test B(%w{ 30 80 04 01 00 00 00 }), expected\n\n    # Missing EOC at the end of contents octets\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 30 80 01 01 FF }))\n    }\n  end\n\n  def test_set\n    encode_decode_test B(%w{ 31 00 }), OpenSSL::ASN1::Set.new([])\n    encode_decode_test B(%w{ 31 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Set.new([\n      OpenSSL::ASN1::Null.new(nil),\n      OpenSSL::ASN1::Sequence.new([]),\n      OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))\n    ])\n    expected = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))])\n    expected.indefinite_length = true\n    encode_decode_test B(%w{ 31 80 04 01 00 00 00 }), expected\n  end\n\n  def test_utctime\n    encode_decode_test B(%w{ 17 0D }) + \"160908234339Z\".b,\n      OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 39))\n\n    # 1950-2049 range is assumed to match RFC 5280's expectation\n    encode_decode_test B(%w{ 17 0D }) + \"490908234339Z\".b,\n      OpenSSL::ASN1::UTCTime.new(Time.utc(2049, 9, 8, 23, 43, 39))\n    encode_decode_test B(%w{ 17 0D }) + \"500908234339Z\".b,\n      OpenSSL::ASN1::UTCTime.new(Time.utc(1950, 9, 8, 23, 43, 39))\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1::UTCTime.new(Time.new(2049, 12, 31, 23, 0, 0, \"-04:00\")).to_der\n    }\n\n    # UTC offset (BER): ASN1_TIME_to_tm() may or may not support it\n    # decode_test B(%w{ 17 11 }) + \"500908234339+0930\".b,\n    #   OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 39, \"+09:30\"))\n    # decode_test B(%w{ 17 0F }) + \"5009082343-0930\".b,\n    #   OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 0, \"-09:30\"))\n\n    # Seconds is omitted (BER)\n    # decode_test B(%w{ 18 0D }) + \"201612081934Z\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0))\n\n    # Fractional seconds is not allowed in UTCTime\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 17 0F }) + \"160908234339.5Z\".b)\n    }\n\n    # Missing \"Z\"\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 17 0C }) + \"500908234339\".b)\n    }\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 17 0D }) + \"500908234339Y\".b)\n    }\n  end\n\n  def test_generalizedtime\n    encode_decode_test B(%w{ 18 0F }) + \"20161208193429Z\".b,\n      OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 29))\n    encode_decode_test B(%w{ 18 0F }) + \"99990908234339Z\".b,\n      OpenSSL::ASN1::GeneralizedTime.new(Time.utc(9999, 9, 8, 23, 43, 39))\n\n    # Fractional seconds (DER). Not supported by ASN1_TIME_to_tm()\n    # because struct tm cannot store it.\n    # encode_decode_test B(%w{ 18 11 }) + \"20161208193439.5Z\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5))\n\n    # UTC offset (BER): ASN1_TIME_to_tm() may or may not support it\n    # decode_test B(%w{ 18 13 }) + \"20161208193439+0930\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 39, \"+09:30\"))\n    # decode_test B(%w{ 18 11 }) + \"201612081934-0930\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, \"-09:30\"))\n    # decode_test B(%w{ 18 11 }) + \"201612081934-09\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, \"-09:00\"))\n\n    # Minutes and seconds are omitted (BER)\n    # decode_test B(%w{ 18 0B }) + \"2016120819Z\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 0, 0))\n    # Fractional hours (BER)\n    # decode_test B(%w{ 18 0D }) + \"2016120819.5Z\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))\n    # Fractional hours with \",\" as the decimal separator (BER)\n    # decode_test B(%w{ 18 0D }) + \"2016120819,5Z\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))\n\n    # Seconds is omitted (BER)\n    # decode_test B(%w{ 18 0D }) + \"201612081934Z\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0))\n    # Fractional minutes (BER)\n    # decode_test B(%w{ 18 0F }) + \"201612081934.5Z\".b,\n    #   OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 30))\n\n    # Missing \"Z\"\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.decode(B(%w{ 18 0F }) + \"20161208193429Y\".b)\n    }\n\n    # Encoding year out of range\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1::GeneralizedTime.new(Time.utc(10000, 9, 8, 23, 43, 39)).to_der\n    }\n  end\n\n  def test_basic_asn1data\n    encode_test B(%w{ 00 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 0, :UNIVERSAL)\n    encode_test B(%w{ 01 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :UNIVERSAL)\n    encode_decode_test B(%w{ 41 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :APPLICATION)\n    encode_decode_test B(%w{ 81 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :CONTEXT_SPECIFIC)\n    encode_decode_test B(%w{ C1 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :PRIVATE)\n    encode_decode_test B(%w{ 1F 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 32, :UNIVERSAL)\n    encode_decode_test B(%w{ 9F C0 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 8224, :CONTEXT_SPECIFIC)\n    encode_decode_test B(%w{ 41 02 AB CD }), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :APPLICATION)\n    encode_decode_test B(%w{ 41 81 80 } + %w{ AB CD } * 64), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 64), 1, :APPLICATION)\n    encode_decode_test B(%w{ 41 82 01 00 } + %w{ AB CD } * 128), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 128), 1, :APPLICATION)\n    encode_decode_test B(%w{ 61 00 }), OpenSSL::ASN1::ASN1Data.new([], 1, :APPLICATION)\n    obj = OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE)], 1, :APPLICATION)\n    obj.indefinite_length = true\n    encode_decode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj\n    obj = OpenSSL::ASN1::ASN1Data.new([\n      OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE),\n      OpenSSL::ASN1::EndOfContent.new\n    ], 1, :APPLICATION)\n    obj.indefinite_length = true\n    encode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj\n    obj = OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :UNIVERSAL)\n    obj.indefinite_length = true\n    assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der }\n  end\n\n  def test_basic_primitive\n    encode_test B(%w{ 00 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 0)\n    encode_test B(%w{ 01 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :UNIVERSAL)\n    encode_test B(%w{ 81 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :CONTEXT_SPECIFIC)\n    encode_test B(%w{ 01 02 AB CD }), OpenSSL::ASN1::Primitive.new(B(%w{ AB CD }), 1)\n    assert_raise(TypeError) { OpenSSL::ASN1::Primitive.new([], 1).to_der }\n\n    prim = OpenSSL::ASN1::Integer.new(50)\n    assert_equal false, prim.indefinite_length\n    assert_not_respond_to prim, :indefinite_length=\n  end\n\n  def test_basic_constructed\n    octet_string = OpenSSL::ASN1::OctetString.new(B(%w{ AB CD }))\n    encode_test B(%w{ 20 00 }), OpenSSL::ASN1::Constructive.new([], 0)\n    encode_test B(%w{ 21 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :UNIVERSAL)\n    encode_test B(%w{ A1 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :CONTEXT_SPECIFIC)\n    encode_test B(%w{ 21 04 04 02 AB CD }), OpenSSL::ASN1::Constructive.new([octet_string], 1)\n    obj = OpenSSL::ASN1::Constructive.new([octet_string], 1)\n    obj.indefinite_length = true\n    encode_decode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj\n    obj = OpenSSL::ASN1::Constructive.new([octet_string, OpenSSL::ASN1::EndOfContent.new], 1)\n    obj.indefinite_length = true\n    encode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj\n  end\n\n  def test_prim_explicit_tagging\n    oct_str = OpenSSL::ASN1::OctetString.new(\"a\", 0, :EXPLICIT)\n    encode_test B(%w{ A0 03 04 01 61 }), oct_str\n    oct_str2 = OpenSSL::ASN1::OctetString.new(\"a\", 1, :EXPLICIT, :APPLICATION)\n    encode_test B(%w{ 61 03 04 01 61 }), oct_str2\n\n    decoded = OpenSSL::ASN1.decode(oct_str2.to_der)\n    assert_equal :APPLICATION, decoded.tag_class\n    assert_equal 1, decoded.tag\n    assert_equal 1, decoded.value.size\n    inner = decoded.value[0]\n    assert_equal OpenSSL::ASN1::OctetString, inner.class\n    assert_equal B(%w{ 61 }), inner.value\n  end\n\n  def test_prim_implicit_tagging\n    int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT)\n    encode_test B(%w{ 80 01 01 }), int\n    int2 = OpenSSL::ASN1::Integer.new(1, 1, :IMPLICIT, :APPLICATION)\n    encode_test B(%w{ 41 01 01 }), int2\n    decoded = OpenSSL::ASN1.decode(int2.to_der)\n    assert_equal :APPLICATION, decoded.tag_class\n    assert_equal 1, decoded.tag\n    assert_equal B(%w{ 01 }), decoded.value\n\n    # Special behavior: Encoding universal types with non-default 'tag'\n    # attribute and nil tagging method.\n    int3 = OpenSSL::ASN1::Integer.new(1, 1)\n    encode_test B(%w{ 01 01 01 }), int3\n  end\n\n  def test_cons_explicit_tagging\n    content = [ OpenSSL::ASN1::PrintableString.new('abc') ]\n    seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT)\n    encode_test B(%w{ A2 07 30 05 13 03 61 62 63 }), seq\n    seq2 = OpenSSL::ASN1::Sequence.new(content, 3, :EXPLICIT, :APPLICATION)\n    encode_test B(%w{ 63 07 30 05 13 03 61 62 63 }), seq2\n\n    content3 = [ OpenSSL::ASN1::PrintableString.new('abc'),\n                 OpenSSL::ASN1::EndOfContent.new() ]\n    seq3 = OpenSSL::ASN1::Sequence.new(content3, 2, :EXPLICIT)\n    seq3.indefinite_length = true\n    encode_test B(%w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 }), seq3\n  end\n\n  def test_cons_implicit_tagging\n    content = [ OpenSSL::ASN1::Null.new(nil) ]\n    seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT)\n    encode_test B(%w{ A1 02 05 00 }), seq\n    seq2 = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT, :APPLICATION)\n    encode_test B(%w{ 61 02 05 00 }), seq2\n\n    content3 = [ OpenSSL::ASN1::Null.new(nil),\n                 OpenSSL::ASN1::EndOfContent.new() ]\n    seq3 = OpenSSL::ASN1::Sequence.new(content3, 1, :IMPLICIT)\n    seq3.indefinite_length = true\n    encode_test B(%w{ A1 80 05 00 00 00 }), seq3\n\n    # Special behavior: Encoding universal types with non-default 'tag'\n    # attribute and nil tagging method.\n    seq4 = OpenSSL::ASN1::Sequence.new([], 1)\n    encode_test B(%w{ 21 00 }), seq4\n  end\n\n  def test_octet_string_constructed_tagging\n    octets = [ OpenSSL::ASN1::OctetString.new('aaa') ]\n    cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT)\n    encode_test B(%w{ A0 05 04 03 61 61 61 }), cons\n\n    octets = [ OpenSSL::ASN1::OctetString.new('aaa'),\n               OpenSSL::ASN1::EndOfContent.new() ]\n    cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT)\n    cons.indefinite_length = true\n    encode_test B(%w{ A0 80 04 03 61 61 61 00 00 }), cons\n  end\n\n  def test_recursive_octet_string_indefinite_length\n    octets_sub1 = [ OpenSSL::ASN1::OctetString.new(\"\\x01\"),\n                    OpenSSL::ASN1::EndOfContent.new() ]\n    octets_sub2 = [ OpenSSL::ASN1::OctetString.new(\"\\x02\"),\n                    OpenSSL::ASN1::EndOfContent.new() ]\n    container1 = OpenSSL::ASN1::Constructive.new(octets_sub1, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)\n    container1.indefinite_length = true\n    container2 = OpenSSL::ASN1::Constructive.new(octets_sub2, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)\n    container2.indefinite_length = true\n    octets3 = OpenSSL::ASN1::OctetString.new(\"\\x03\")\n\n    octets = [ container1, container2, octets3,\n               OpenSSL::ASN1::EndOfContent.new() ]\n    cons = OpenSSL::ASN1::Constructive.new(octets, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)\n    cons.indefinite_length = true\n    raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 })\n    assert_equal(raw, cons.to_der)\n    assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)\n  end\n\n  def test_recursive_octet_string_parse\n    raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 })\n    asn1 = OpenSSL::ASN1.decode(raw)\n    assert_equal(OpenSSL::ASN1::Constructive, asn1.class)\n    assert_universal(OpenSSL::ASN1::OCTET_STRING, asn1)\n    assert_equal(true, asn1.indefinite_length)\n    assert_equal(3, asn1.value.size)\n    nested1 = asn1.value[0]\n    assert_equal(OpenSSL::ASN1::Constructive, nested1.class)\n    assert_universal(OpenSSL::ASN1::OCTET_STRING, nested1)\n    assert_equal(true, nested1.indefinite_length)\n    assert_equal(1, nested1.value.size)\n    oct1 = nested1.value[0]\n    assert_universal(OpenSSL::ASN1::OCTET_STRING, oct1)\n    assert_equal(false, oct1.indefinite_length)\n    nested2 = asn1.value[1]\n    assert_equal(OpenSSL::ASN1::Constructive, nested2.class)\n    assert_universal(OpenSSL::ASN1::OCTET_STRING, nested2)\n    assert_equal(true, nested2.indefinite_length)\n    assert_equal(1, nested2.value.size)\n    oct2 = nested2.value[0]\n    assert_universal(OpenSSL::ASN1::OCTET_STRING, oct2)\n    assert_equal(false, oct2.indefinite_length)\n    oct3 = asn1.value[2]\n    assert_universal(OpenSSL::ASN1::OCTET_STRING, oct3)\n    assert_equal(false, oct3.indefinite_length)\n  end\n\n  def test_decode_constructed_overread\n    test = %w{ 31 06 31 02 30 02 05 00 }\n    #                          ^ <- invalid\n    raw = [test.join].pack(\"H*\")\n    ret = []\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.traverse(raw) { |x| ret << x }\n    }\n    assert_equal 2, ret.size\n    assert_equal 17, ret[0][6]\n    assert_equal 17, ret[1][6]\n\n    test = %w{ 31 80 30 03 00 00 }\n    #                    ^ <- invalid\n    raw = [test.join].pack(\"H*\")\n    ret = []\n    assert_raise(OpenSSL::ASN1::ASN1Error) {\n      OpenSSL::ASN1.traverse(raw) { |x| ret << x }\n    }\n    assert_equal 1, ret.size\n    assert_equal 17, ret[0][6]\n  end\n\n  def test_constructive_each\n    data = [OpenSSL::ASN1::Integer.new(0), OpenSSL::ASN1::Integer.new(1)]\n    seq = OpenSSL::ASN1::Sequence.new data\n\n    assert_equal data, seq.entries\n  end\n\n  # Very time consuming test.\n  # def test_gc_stress\n  #   assert_ruby_status(['--disable-gems', '-eGC.stress=true', '-erequire \"openssl.so\"'])\n  # end\n\n  private\n\n  def B(ary)\n    [ary.join].pack(\"H*\")\n  end\n\n  def assert_asn1_equal(a, b)\n    assert_equal a.class, b.class\n    assert_equal a.tag, b.tag\n    assert_equal a.tag_class, b.tag_class\n    assert_equal a.indefinite_length, b.indefinite_length\n    assert_equal a.unused_bits, b.unused_bits if a.respond_to?(:unused_bits)\n    case a.value\n    when Array\n      a.value.each_with_index { |ai, i|\n        assert_asn1_equal ai, b.value[i]\n      }\n    else\n      if OpenSSL::ASN1::ObjectId === a\n        assert_equal a.oid, b.oid\n      else\n        assert_equal a.value, b.value\n      end\n    end\n    assert_equal a.to_der, b.to_der\n  end\n\n  def encode_test(der, obj)\n    assert_equal der, obj.to_der\n  end\n\n  def decode_test(der, obj)\n    decoded = OpenSSL::ASN1.decode(der)\n    assert_asn1_equal obj, decoded\n    decoded\n  end\n\n  def encode_decode_test(der, obj)\n    encode_test(der, obj)\n    decode_test(der, obj)\n  end\n\n  def assert_universal(tag, asn1)\n    assert_equal(tag, asn1.tag)\n    if asn1.respond_to?(:tagging)\n      assert_nil(asn1.tagging)\n    end\n    assert_equal(:UNIVERSAL, asn1.tag_class)\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_bn.rb",
    "content": "# coding: us-ascii\n# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestBN < OpenSSL::TestCase\n  def setup\n    super\n    @e1 = OpenSSL::BN.new(999.to_s(16), 16) # OpenSSL::BN.new(str, 16) must be most stable\n    @e2 = OpenSSL::BN.new(\"-\" + 999.to_s(16), 16)\n    @e3 = OpenSSL::BN.new((2**107-1).to_s(16), 16)\n    @e4 = OpenSSL::BN.new(\"-\" + (2**107-1).to_s(16), 16)\n  end\n\n  def test_new\n    assert_raise(ArgumentError) { OpenSSL::BN.new }\n    assert_raise(ArgumentError) { OpenSSL::BN.new(nil) }\n    assert_raise(ArgumentError) { OpenSSL::BN.new(nil, 2) }\n\n    assert_equal(@e1, OpenSSL::BN.new(\"999\"))\n    assert_equal(@e1, OpenSSL::BN.new(\"999\", 10))\n    assert_equal(@e1, OpenSSL::BN.new(\"\\x03\\xE7\", 2))\n    assert_equal(@e1, OpenSSL::BN.new(\"\\x00\\x00\\x00\\x02\\x03\\xE7\", 0))\n    assert_equal(@e2, OpenSSL::BN.new(\"-999\"))\n    assert_equal(@e2, OpenSSL::BN.new(\"-999\", 10))\n    assert_equal(@e2, OpenSSL::BN.new(\"\\x00\\x00\\x00\\x02\\x83\\xE7\", 0))\n    assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s))\n    assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s, 10))\n    assert_equal(@e3, OpenSSL::BN.new(\"\\a\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\", 2))\n    assert_equal(@e3, OpenSSL::BN.new(\"\\x00\\x00\\x00\\x0E\\a\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\", 0))\n    assert_equal(@e4, OpenSSL::BN.new(\"-\" + (2**107-1).to_s))\n    assert_equal(@e4, OpenSSL::BN.new(\"-\" + (2**107-1).to_s, 10))\n    assert_equal(@e4, OpenSSL::BN.new(\"\\x00\\x00\\x00\\x0E\\x87\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\", 0))\n\n    e1copy = OpenSSL::BN.new(@e1)\n    assert_equal(@e1, e1copy)\n    e1copy.clear_bit!(0) #=> 998\n    assert_not_equal(@e1, e1copy)\n\n    assert_equal(@e1, OpenSSL::BN.new(999))\n    assert_equal(@e2, OpenSSL::BN.new(-999))\n    assert_equal(@e3, OpenSSL::BN.new(2**107-1))\n    assert_equal(@e4, OpenSSL::BN.new(-(2**107-1)))\n\n    assert_equal(@e1, 999.to_bn)\n    assert_equal(@e2, -999.to_bn)\n    assert_equal(@e3, (2**107-1).to_bn)\n    assert_equal(@e4, (-(2**107-1)).to_bn)\n  end\n\n  def test_to_str\n    assert_equal(\"999\", @e1.to_s(10))\n    assert_equal(\"-999\", @e2.to_s(10))\n    assert_equal((2**107-1).to_s, @e3.to_s(10))\n    assert_equal((-(2**107-1)).to_s, @e4.to_s(10))\n    assert_equal(\"999\", @e1.to_s)\n\n    assert_equal(\"03E7\", @e1.to_s(16))\n    assert_equal(\"-03E7\", @e2.to_s(16))\n    assert_equal(\"07FFFFFFFFFFFFFFFFFFFFFFFFFF\", @e3.to_s(16))\n    assert_equal(\"-07FFFFFFFFFFFFFFFFFFFFFFFFFF\", @e4.to_s(16))\n\n    assert_equal(\"\\x03\\xe7\", @e1.to_s(2))\n    assert_equal(\"\\x03\\xe7\", @e2.to_s(2))\n    assert_equal(\"\\x07\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\", @e3.to_s(2))\n    assert_equal(\"\\x07\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\", @e4.to_s(2))\n\n    assert_equal(\"\\x00\\x00\\x00\\x02\\x03\\xe7\", @e1.to_s(0))\n    assert_equal(\"\\x00\\x00\\x00\\x02\\x83\\xe7\", @e2.to_s(0))\n    assert_equal(\"\\x00\\x00\\x00\\x0e\\x07\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\", @e3.to_s(0))\n    assert_equal(\"\\x00\\x00\\x00\\x0e\\x87\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\", @e4.to_s(0))\n  end\n\n  def test_to_int\n    assert_equal(999, @e1.to_i)\n    assert_equal(-999, @e2.to_i)\n    assert_equal(2**107-1, @e3.to_i)\n    assert_equal(-(2**107-1), @e4.to_i)\n\n    assert_equal(999, @e1.to_int)\n  end\n\n  def test_coerce\n    assert_equal([\"\", \"-999\"], @e2.coerce(\"\"))\n    assert_equal([1000, -999], @e2.coerce(1000))\n    assert_raise(TypeError) { @e2.coerce(Class.new.new) }\n  end\n\n  def test_zero_p\n    assert_equal(true, 0.to_bn.zero?)\n    assert_equal(false, 1.to_bn.zero?)\n  end\n\n  def test_one_p\n    assert_equal(true, 1.to_bn.one?)\n    assert_equal(false, 2.to_bn.one?)\n  end\n\n  def test_odd_p\n    assert_equal(true, 1.to_bn.odd?)\n    assert_equal(false, 2.to_bn.odd?)\n  end\n\n  def test_negative_p\n    assert_equal(false, 0.to_bn.negative?)\n    assert_equal(false, @e1.negative?)\n    assert_equal(true, @e2.negative?)\n  end\n\n  def test_sqr\n    assert_equal(1, 1.to_bn.sqr)\n    assert_equal(100, 10.to_bn.sqr)\n  end\n\n  def test_four_ops\n    assert_equal(3, 1.to_bn + 2)\n    assert_equal(-1, 1.to_bn + -2)\n    assert_equal(-1, 1.to_bn - 2)\n    assert_equal(3, 1.to_bn - -2)\n    assert_equal(2, 1.to_bn * 2)\n    assert_equal(-2, 1.to_bn * -2)\n    assert_equal([0, 1], 1.to_bn / 2)\n    assert_equal([2, 0], 2.to_bn / 1)\n    assert_raise(OpenSSL::BNError) { 1.to_bn / 0 }\n  end\n\n  def test_unary_plus_minus\n    assert_equal(999, +@e1)\n    assert_equal(-999, +@e2)\n    assert_equal(-999, -@e1)\n    assert_equal(+999, -@e2)\n\n    # These methods create new BN instances due to BN mutability\n    # Ensure that the instance isn't the same\n    e1_plus = +@e1\n    e1_minus = -@e1\n    assert_equal(false, @e1.equal?(e1_plus))\n    assert_equal(true, @e1 == e1_plus)\n    assert_equal(false, @e1.equal?(e1_minus))\n  end\n\n  def test_abs\n    assert_equal(@e1, @e2.abs)\n    assert_equal(@e3, @e4.abs)\n    assert_not_equal(@e2, @e2.abs)\n    assert_not_equal(@e4, @e4.abs)\n    assert_equal(false, @e2.abs.negative?)\n    assert_equal(false, @e4.abs.negative?)\n    assert_equal(true, (-@e1.abs).negative?)\n    assert_equal(true, (-@e2.abs).negative?)\n    assert_equal(true, (-@e3.abs).negative?)\n    assert_equal(true, (-@e4.abs).negative?)\n  end\n\n  def test_mod\n    assert_equal(1, 1.to_bn % 2)\n    assert_equal(0, 2.to_bn % 1)\n    assert_equal(-2, -2.to_bn % 7)\n  end\n\n  def test_exp\n    assert_equal(1, 1.to_bn ** 5)\n    assert_equal(32, 2.to_bn ** 5)\n  end\n\n  def test_gcd\n    assert_equal(1, 7.to_bn.gcd(5))\n    assert_equal(8, 24.to_bn.gcd(16))\n  end\n\n  def test_mod_sqr\n    assert_equal(4, 3.to_bn.mod_sqr(5))\n    assert_equal(0, 59.to_bn.mod_sqr(59))\n  end\n\n  def test_mod_sqrt\n    assert_equal(4, 4.to_bn.mod_sqrt(5).mod_sqr(5))\n    # One of 189484 or 326277 is returned as a square root of 2 (mod 515761).\n    assert_equal(2, 2.to_bn.mod_sqrt(515761).mod_sqr(515761))\n    assert_equal(0, 5.to_bn.mod_sqrt(5))\n    assert_raise(OpenSSL::BNError) { 3.to_bn.mod_sqrt(5) }\n  end\n\n  def test_mod_inverse\n    assert_equal(2, 3.to_bn.mod_inverse(5))\n    assert_raise(OpenSSL::BNError) { 3.to_bn.mod_inverse(6) }\n  end\n\n  def test_mod_add\n    assert_equal(1, 3.to_bn.mod_add(5, 7))\n    assert_equal(2, 3.to_bn.mod_add(5, 3))\n    assert_equal(5, 3.to_bn.mod_add(-5, 7))\n  end\n\n  def test_mod_sub\n    assert_equal(1, 11.to_bn.mod_sub(3, 7))\n    assert_equal(2, 11.to_bn.mod_sub(3, 3))\n    assert_equal(5, 3.to_bn.mod_sub(5, 7))\n  end\n\n  def test_mod_mul\n    assert_equal(1, 2.to_bn.mod_mul(4, 7))\n    assert_equal(5, 2.to_bn.mod_mul(-1, 7))\n  end\n\n  def test_mod_exp\n    assert_equal(1, 3.to_bn.mod_exp(2, 8))\n    assert_equal(4, 2.to_bn.mod_exp(5, 7))\n  end\n\n  def test_bit_operations\n    e = 0b10010010.to_bn\n    assert_equal(0b10010011, e.set_bit!(0))\n    assert_equal(0b10010011, e.set_bit!(1))\n    assert_equal(0b1010010011, e.set_bit!(9))\n\n    e = 0b10010010.to_bn\n    assert_equal(0b10010010, e.clear_bit!(0))\n    assert_equal(0b10010000, e.clear_bit!(1))\n\n    e = 0b10010010.to_bn\n    assert_equal(0b10010010, e.mask_bits!(8))\n    assert_equal(0b10, e.mask_bits!(3))\n\n    e = 0b10010010.to_bn\n    assert_equal(false, e.bit_set?(0))\n    assert_equal(true, e.bit_set?(1))\n    assert_equal(false, e.bit_set?(1000))\n\n    e = 0b10010010.to_bn\n    assert_equal(0b1001001000, e << 2)\n    assert_equal(0b10010010, e)\n    assert_equal(0b1001001000, e.lshift!(2))\n    assert_equal(0b1001001000, e)\n\n    e = 0b10010010.to_bn\n    assert_equal(0b100100, e >> 2)\n    assert_equal(0b10010010, e)\n    assert_equal(0b100100, e.rshift!(2))\n    assert_equal(0b100100, e)\n  end\n\n  def test_random\n    10.times {\n      r1 = OpenSSL::BN.rand(8)\n      assert_include(128..255, r1)\n      r2 = OpenSSL::BN.rand(8, -1)\n      assert_include(0..255, r2)\n      r3 = OpenSSL::BN.rand(8, 1)\n      assert_include(192..255, r3)\n      r4 = OpenSSL::BN.rand(8, 1, true)\n      assert_include(192..255, r4)\n      assert_equal(true, r4.odd?)\n\n      r5 = OpenSSL::BN.rand_range(256)\n      assert_include(0..255, r5)\n    }\n\n    # Aliases\n    assert_include(128..255, OpenSSL::BN.pseudo_rand(8))\n    assert_include(0..255, OpenSSL::BN.pseudo_rand_range(256))\n  end\n\n  begin\n    require \"prime\"\n\n    def test_prime\n      p1 = OpenSSL::BN.generate_prime(32)\n      assert_include(0...2**32, p1)\n      assert_equal(true, Prime.prime?(p1.to_i))\n      p2 = OpenSSL::BN.generate_prime(32, true)\n      assert_equal(true, Prime.prime?((p2.to_i - 1) / 2))\n      p3 = OpenSSL::BN.generate_prime(32, false, 4)\n      assert_equal(1, p3 % 4)\n      p4 = OpenSSL::BN.generate_prime(32, false, 4, 3)\n      assert_equal(3, p4 % 4)\n\n      assert_equal(true, p1.prime?)\n      assert_equal(true, p2.prime?)\n      assert_equal(true, p3.prime?)\n      assert_equal(true, p4.prime?)\n      assert_equal(true, @e3.prime?)\n      assert_equal(true, @e3.prime_fasttest?)\n    end\n  rescue LoadError\n    # prime is the bundled gems at Ruby 3.1\n  end\n\n  def test_num_bits_bytes\n    assert_equal(10, @e1.num_bits)\n    assert_equal(2, @e1.num_bytes)\n    assert_equal(107, @e3.num_bits)\n    assert_equal(14, @e3.num_bytes)\n    assert_equal(0, 0.to_bn.num_bits)\n    assert_equal(0, 0.to_bn.num_bytes)\n    assert_equal(9, -256.to_bn.num_bits)\n    assert_equal(2, -256.to_bn.num_bytes)\n  end\n\n  def test_comparison\n    assert_equal(false, @e1 == nil)\n    assert_equal(false, @e1 == -999)\n    assert_equal(true, @e1 == 999)\n    assert_equal(true, @e1 == 999.to_bn)\n    assert_equal(false, @e1.eql?(nil))\n    assert_equal(false, @e1.eql?(999))\n    assert_equal(true, @e1.eql?(999.to_bn))\n    assert_equal(@e1.hash, 999.to_bn.hash)\n    assert_not_equal(@e1.hash, @e3.hash)\n    assert_equal(0, @e1.cmp(999))\n    assert_equal(1, @e1.cmp(-999))\n    assert_equal(0, @e1.ucmp(999))\n    assert_equal(0, @e1.ucmp(-999))\n    assert_instance_of(String, @e1.hash.to_s)\n  end\n\n  def test_argument_error\n    bug15760 = '[ruby-core:92231] [Bug #15760]'\n    assert_raise(ArgumentError, bug15760) { OpenSSL::BN.new(nil, 2) }\n  end\n\n  def test_get_flags_and_set_flags\n    return if aws_lc? # AWS-LC does not support BN::CONSTTIME.\n\n    e = OpenSSL::BN.new(999)\n\n    assert_equal(0, e.get_flags(OpenSSL::BN::CONSTTIME))\n\n    e.set_flags(OpenSSL::BN::CONSTTIME)\n    assert_equal(OpenSSL::BN::CONSTTIME, e.get_flags(OpenSSL::BN::CONSTTIME))\n\n    b = OpenSSL::BN.new(2)\n    m = OpenSSL::BN.new(99)\n    assert_equal(\"17\", b.mod_exp(e, m).to_s)\n\n    # mod_exp fails when m is even and any argument has CONSTTIME flag\n    m = OpenSSL::BN.new(98)\n    assert_raise(OpenSSL::BNError) do\n      b.mod_exp(e, m)\n    end\n\n    # It looks like flags cannot be removed once enabled\n    e.set_flags(0)\n    assert_equal(4, e.get_flags(OpenSSL::BN::CONSTTIME))\n  end\n\n  if defined?(Ractor) && respond_to?(:ractor)\n    unless Ractor.method_defined?(:value) # Ruby 3.4 or earlier\n      using Module.new {\n        refine Ractor do\n          alias value take\n        end\n      }\n    end\n\n    ractor\n    def test_ractor\n      assert_equal(@e1, Ractor.new { OpenSSL::BN.new(\"999\") }.value)\n      assert_equal(@e3, Ractor.new { OpenSSL::BN.new(\"\\a\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\", 2) }.value)\n      assert_equal(\"999\", Ractor.new(@e1) { |e1| e1.to_s }.value)\n      assert_equal(\"07FFFFFFFFFFFFFFFFFFFFFFFFFF\", Ractor.new(@e3) { |e3| e3.to_s(16) }.value)\n      assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.value)\n      assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.value)\n      assert_equal(false, Ractor.new  { 1.to_bn.zero? }.value)\n      assert_equal(true, Ractor.new { 1.to_bn.one? }.value)\n      assert_equal(true, Ractor.new(@e2) { _1.negative? }.value)\n      assert_equal(\"-03E7\", Ractor.new(@e2) { _1.to_s(16) }.value)\n      assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.value)\n      assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.value)\n      assert_equal(true, Ractor.new { 0.to_bn.zero? }.value)\n      assert_equal(true, Ractor.new { 1.to_bn.one? }.value )\n      assert_equal(false,Ractor.new { 2.to_bn.odd? }.value)\n      assert_equal(true, Ractor.new(@e2) { _1.negative? }.value)\n      assert_include(128..255, Ractor.new { OpenSSL::BN.rand(8)}.value)\n      assert_include(0...2**32, Ractor.new { OpenSSL::BN.generate_prime(32) }.value)\n      if !aws_lc? # AWS-LC does not support BN::CONSTTIME.\n        assert_equal(0, Ractor.new { OpenSSL::BN.new(999).get_flags(OpenSSL::BN::CONSTTIME) }.value)\n      end\n      # test if shareable when frozen\n      assert Ractor.shareable?(@e1.freeze)\n    end\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_buffering.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestBuffering < OpenSSL::TestCase\n  class IO\n    include OpenSSL::Buffering\n\n    attr_accessor :sync\n\n    def initialize\n      @io = Buffer.new\n      def @io.sync\n        true\n      end\n\n      super\n\n      @sync = false\n    end\n\n    def string\n      @io\n    end\n\n    def sysread(size)\n      str = @io.slice!(0, size)\n      raise EOFError if str.empty?\n      str\n    end\n\n    def syswrite(str)\n      @io.append_as_bytes(str)\n      str.size\n    end\n  end\n\n  def setup\n    super\n    @io = IO.new\n  end\n\n  def test_encoding\n    @io.write '😊'\n    @io.flush\n\n    assert_equal @io.string.encoding, Encoding::BINARY\n  end\n\n  def test_flush\n    @io.write 'a'\n\n    assert_not_predicate @io, :sync\n    assert_empty @io.string\n\n    assert_equal @io, @io.flush\n\n    assert_not_predicate @io, :sync\n    assert_equal 'a', @io.string\n  end\n\n  def test_flush_error\n    @io.write 'a'\n\n    assert_not_predicate @io, :sync\n    assert_empty @io.string\n\n    def @io.syswrite *a\n      raise SystemCallError, 'fail'\n    end\n\n    assert_raise SystemCallError do\n      @io.flush\n    end\n\n    assert_not_predicate @io, :sync, 'sync must not change'\n  end\n\n  def test_getc\n    @io.syswrite('abc')\n    assert_equal(?a, @io.getc)\n    assert_equal(?b, @io.getc)\n    assert_equal(?c, @io.getc)\n  end\n\n  def test_each_byte\n    @io.syswrite('abc')\n    res = []\n    @io.each_byte do |c|\n      res << c\n    end\n    assert_equal([97, 98, 99], res)\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_cipher.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestCipher < OpenSSL::TestCase\n  module Helper\n    def has_cipher?(name)\n      @ciphers ||= OpenSSL::Cipher.ciphers\n      @ciphers.include?(name)\n    end\n  end\n  include Helper\n  extend Helper\n\n  def test_encrypt_decrypt\n    # NIST SP 800-38A F.2.1\n    key = [\"2b7e151628aed2a6abf7158809cf4f3c\"].pack(\"H*\")\n    iv =  [\"000102030405060708090a0b0c0d0e0f\"].pack(\"H*\")\n    pt =  [\"6bc1bee22e409f96e93d7e117393172a\" \\\n           \"ae2d8a571e03ac9c9eb76fac45af8e51\"].pack(\"H*\")\n    ct =  [\"7649abac8119b246cee98e9b12e9197d\" \\\n           \"5086cb9b507219ee95db113a917678b2\"].pack(\"H*\")\n    cipher = new_encryptor(\"aes-128-cbc\", key: key, iv: iv, padding: 0)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    cipher = new_decryptor(\"aes-128-cbc\", key: key, iv: iv, padding: 0)\n    assert_equal pt, cipher.update(ct) << cipher.final\n  end\n\n  def test_pkcs5_keyivgen\n    pass = \"\\x00\" * 8\n    salt = \"\\x01\" * 8\n    num = 2048\n    pt = \"data to be encrypted\"\n    cipher = OpenSSL::Cipher.new(\"AES-256-CBC\").encrypt\n    cipher.pkcs5_keyivgen(pass, salt, num, \"SHA256\")\n    s1 = cipher.update(pt) << cipher.final\n\n    d1 = num.times.inject(pass + salt) {|out, _| OpenSSL::Digest.digest('SHA256', out) }\n    d2 = num.times.inject(d1 + pass + salt) {|out, _| OpenSSL::Digest.digest('SHA256', out) }\n    key = (d1 + d2)[0, 32]\n    iv = (d1 + d2)[32, 16]\n    cipher = new_encryptor(\"AES-256-CBC\", key: key, iv: iv)\n    s2 = cipher.update(pt) << cipher.final\n\n    assert_equal s1, s2\n\n    cipher2 = OpenSSL::Cipher.new(\"AES-256-CBC\").encrypt\n    assert_raise(ArgumentError) { cipher2.pkcs5_keyivgen(pass, salt, -1, \"SHA256\") }\n  end\n\n  def test_info\n    cipher = OpenSSL::Cipher.new(\"AES-256-CBC\").encrypt\n    assert_equal \"AES-256-CBC\", cipher.name\n    assert_equal 32, cipher.key_len\n    assert_equal 16, cipher.iv_len\n  end\n\n  def test_dup\n    cipher = OpenSSL::Cipher.new(\"aes-128-cbc\").encrypt\n    assert_equal cipher.name, cipher.dup.name\n    cipher.encrypt\n    cipher.random_key\n    cipher.random_iv\n    tmpc = cipher.dup\n    s1 = cipher.update(\"data\") + cipher.final\n    s2 = tmpc.update(\"data\") + tmpc.final\n    assert_equal(s1, s2, \"encrypt dup\")\n  end\n\n  def test_reset\n    cipher = OpenSSL::Cipher.new(\"aes-128-cbc\").encrypt\n    cipher.encrypt\n    cipher.random_key\n    cipher.random_iv\n    s1 = cipher.update(\"data\") + cipher.final\n    cipher.reset\n    s2 = cipher.update(\"data\") + cipher.final\n    assert_equal(s1, s2, \"encrypt reset\")\n  end\n\n  def test_key_iv_set\n    cipher = OpenSSL::Cipher.new(\"AES-256-CBC\").encrypt\n    assert_raise(ArgumentError) { cipher.key = \"\\x01\" * 31 }\n    assert_nothing_raised { cipher.key = \"\\x01\" * 32 }\n    assert_raise(ArgumentError) { cipher.key = \"\\x01\" * 33 }\n    assert_raise(ArgumentError) { cipher.iv = \"\\x01\" * 15 }\n    assert_nothing_raised { cipher.iv = \"\\x01\" * 16 }\n    assert_raise(ArgumentError) { cipher.iv = \"\\x01\" * 17 }\n  end\n\n  def test_random_key_iv\n    data = \"data\"\n    s1, s2 = 2.times.map do\n      cipher = OpenSSL::Cipher.new(\"aes-128-cbc\").encrypt\n      cipher.random_key\n      cipher.iv = \"\\x01\" * 16\n      cipher.update(data) << cipher.final\n    end\n    assert_not_equal s1, s2\n\n    s1, s2 = 2.times.map do\n      cipher = OpenSSL::Cipher.new(\"aes-128-cbc\").encrypt\n      cipher.key = \"\\x01\" * 16\n      cipher.random_iv\n      cipher.update(data) << cipher.final\n    end\n    assert_not_equal s1, s2\n  end\n\n  def test_initialize\n    cipher = OpenSSL::Cipher.new(\"AES-256-CBC\")\n    assert_raise(RuntimeError) { cipher.__send__(:initialize, \"AES-256-CBC\") }\n    assert_raise(RuntimeError) { OpenSSL::Cipher.allocate.final }\n    assert_raise(OpenSSL::Cipher::CipherError) {\n      OpenSSL::Cipher.new(\"no such algorithm\")\n    }\n  end\n\n  def test_ctr_if_exists\n    # NIST SP 800-38A F.5.1\n    key = [\"2b7e151628aed2a6abf7158809cf4f3c\"].pack(\"H*\")\n    iv =  [\"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff\"].pack(\"H*\")\n    pt =  [\"6bc1bee22e409f96e93d7e117393172a\" \\\n           \"ae2d8a571e03ac9c9eb76fac45af8e51\"].pack(\"H*\")\n    ct =  [\"874d6191b620e3261bef6864990db6ce\" \\\n           \"9806f66b7970fdff8617187bb9fffdff\"].pack(\"H*\")\n    cipher = new_encryptor(\"aes-128-ctr\", key: key, iv: iv, padding: 0)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    cipher = new_decryptor(\"aes-128-ctr\", key: key, iv: iv, padding: 0)\n    assert_equal pt, cipher.update(ct) << cipher.final\n  end\n\n  def test_update_with_buffer\n    cipher = OpenSSL::Cipher.new(\"aes-128-ecb\").encrypt\n    cipher.random_key\n    expected = cipher.update(\"data\" * 10) << cipher.final\n    assert_equal 48, expected.bytesize\n\n    # Buffer is supplied\n    cipher.reset\n    buf = String.new\n    assert_same buf, cipher.update(\"data\" * 10, buf)\n    assert_equal 32, buf.bytesize\n    assert_equal expected, buf + cipher.final\n\n    # Buffer is frozen\n    cipher.reset\n    assert_raise(FrozenError) { cipher.update(\"data\", String.new.freeze) }\n\n    # Buffer is a shared string [ruby-core:120141] [Bug #20937]\n    cipher.reset\n    buf = \"x\".b * 1024\n    shared = buf[-(\"data\".bytesize * 10 + 32)..-1]\n    assert_same shared, cipher.update(\"data\" * 10, shared)\n    assert_equal expected, shared + cipher.final\n  end\n\n  def test_ciphers\n    ciphers = OpenSSL::Cipher.ciphers\n    assert_kind_of Array, ciphers\n    assert_include ciphers, \"aes-128-cbc\"\n    assert_include ciphers, \"aes128\" # alias of aes-128-cbc\n    assert_include ciphers, \"aes-128-gcm\"\n  end\n\n  def test_AES\n    pt = File.read(__FILE__)\n    %w(ecb cbc cfb ofb).each{|mode|\n      c1 = OpenSSL::Cipher.new(\"aes-256-#{mode}\")\n      c1.encrypt\n      c1.pkcs5_keyivgen(\"passwd\", \"12345678\", 10000, \"SHA256\")\n      ct = c1.update(pt) + c1.final\n\n      c2 = OpenSSL::Cipher.new(\"aes-256-#{mode}\")\n      c2.decrypt\n      c2.pkcs5_keyivgen(\"passwd\", \"12345678\", 10000, \"SHA256\")\n      assert_equal(pt, c2.update(ct) + c2.final)\n    }\n  end\n\n  def test_update_raise_if_key_not_set\n    assert_raise(OpenSSL::Cipher::CipherError) do\n      # it caused OpenSSL SEGV by uninitialized key [Bug #2768]\n      OpenSSL::Cipher.new(\"aes-128-ecb\").update \".\" * 17\n    end\n  end\n\n  def test_auth_tag_error_inheritance\n    assert_equal OpenSSL::Cipher::CipherError, OpenSSL::Cipher::AuthTagError.superclass\n  end\n\n  def test_authenticated\n    cipher = OpenSSL::Cipher.new('aes-128-gcm')\n    assert_predicate(cipher, :authenticated?)\n    cipher = OpenSSL::Cipher.new('aes-128-cbc')\n    assert_not_predicate(cipher, :authenticated?)\n  end\n\n  def test_aes_ccm\n    # RFC 3610 Section 8, Test Case 1\n    key = [\"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf\"].pack(\"H*\")\n    iv =  [\"00000003020100a0a1a2a3a4a5\"].pack(\"H*\")\n    aad = [\"0001020304050607\"].pack(\"H*\")\n    pt =  [\"08090a0b0c0d0e0f101112131415161718191a1b1c1d1e\"].pack(\"H*\")\n    ct =  [\"588c979a61c663d2f066d0c2c0f989806d5f6b61dac384\"].pack(\"H*\")\n    tag = [\"17e8d12cfdf926e0\"].pack(\"H*\")\n\n    kwargs = {auth_tag_len: 8, iv_len: 13, key: key, iv: iv}\n    cipher = new_encryptor(\"aes-128-ccm\", **kwargs, ccm_data_len: pt.length, auth_data: aad)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    assert_equal tag, cipher.auth_tag\n    cipher = new_decryptor(\"aes-128-ccm\", **kwargs, ccm_data_len: ct.length, auth_tag: tag, auth_data: aad)\n    assert_equal pt, cipher.update(ct) << cipher.final\n\n    # truncated tag is accepted\n    cipher = new_encryptor(\"aes-128-ccm\", **kwargs, ccm_data_len: pt.length, auth_data: aad)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    assert_equal tag[0, 8], cipher.auth_tag(8)\n    cipher = new_decryptor(\"aes-128-ccm\", **kwargs, ccm_data_len: ct.length, auth_tag: tag[0, 8], auth_data: aad)\n    assert_equal pt, cipher.update(ct) << cipher.final\n\n    # wrong tag is rejected - in CCM, authentication happens during update, but\n    # we consider this a general CipherError since update failures can have various causes\n    tag2 = tag.dup\n    tag2.setbyte(-1, (tag2.getbyte(-1) + 1) & 0xff)\n    cipher = new_decryptor(\"aes-128-ccm\", **kwargs, ccm_data_len: ct.length, auth_tag: tag2, auth_data: aad)\n    assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(ct) }\n\n    # wrong aad is rejected\n    aad2 = aad[0..-2] << aad[-1].succ\n    cipher = new_decryptor(\"aes-128-ccm\", **kwargs, ccm_data_len: ct.length, auth_tag: tag, auth_data: aad2)\n    assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(ct) }\n\n    # wrong ciphertext is rejected\n    ct2 = ct[0..-2] << ct[-1].succ\n    cipher = new_decryptor(\"aes-128-ccm\", **kwargs, ccm_data_len: ct2.length, auth_tag: tag, auth_data: aad)\n    assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(ct2) }\n  end if has_cipher?(\"aes-128-ccm\") &&\n         OpenSSL::Cipher.new(\"aes-128-ccm\").authenticated? &&\n         openssl?(1, 1, 1, 0x03, 0xf) # version >= 1.1.1c\n\n  def test_aes_gcm\n    # GCM spec Appendix B Test Case 4\n    key = [\"feffe9928665731c6d6a8f9467308308\"].pack(\"H*\")\n    iv =  [\"cafebabefacedbaddecaf888\"].pack(\"H*\")\n    aad = [\"feedfacedeadbeeffeedfacedeadbeef\" \\\n           \"abaddad2\"].pack(\"H*\")\n    pt =  [\"d9313225f88406e5a55909c5aff5269a\" \\\n           \"86a7a9531534f7da2e4c303d8a318a72\" \\\n           \"1c3c0c95956809532fcf0e2449a6b525\" \\\n           \"b16aedf5aa0de657ba637b39\"].pack(\"H*\")\n    ct =  [\"42831ec2217774244b7221b784d0d49c\" \\\n           \"e3aa212f2c02a4e035c17e2329aca12e\" \\\n           \"21d514b25466931c7d8f6a5aac84aa05\" \\\n           \"1ba30b396a0aac973d58e091\"].pack(\"H*\")\n    tag = [\"5bc94fbc3221a5db94fae95ae7121a47\"].pack(\"H*\")\n\n    cipher = new_encryptor(\"aes-128-gcm\", key: key, iv: iv, auth_data: aad)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    assert_equal tag, cipher.auth_tag\n    cipher = new_decryptor(\"aes-128-gcm\", key: key, iv: iv, auth_tag: tag, auth_data: aad)\n    assert_equal pt, cipher.update(ct) << cipher.final\n\n    # truncated tag is accepted\n    cipher = new_encryptor(\"aes-128-gcm\", key: key, iv: iv, auth_data: aad)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    assert_equal tag[0, 8], cipher.auth_tag(8)\n    cipher = new_decryptor(\"aes-128-gcm\", key: key, iv: iv, auth_tag: tag[0, 8], auth_data: aad)\n    assert_equal pt, cipher.update(ct) << cipher.final\n\n    # wrong tag is rejected\n    tag2 = tag.dup\n    tag2.setbyte(-1, (tag2.getbyte(-1) + 1) & 0xff)\n    cipher = new_decryptor(\"aes-128-gcm\", key: key, iv: iv, auth_tag: tag2, auth_data: aad)\n    cipher.update(ct)\n    assert_raise(OpenSSL::Cipher::AuthTagError) { cipher.final }\n\n    # wrong aad is rejected\n    aad2 = aad[0..-2] << aad[-1].succ\n    cipher = new_decryptor(\"aes-128-gcm\", key: key, iv: iv, auth_tag: tag, auth_data: aad2)\n    cipher.update(ct)\n    assert_raise(OpenSSL::Cipher::AuthTagError) { cipher.final }\n\n    # wrong ciphertext is rejected\n    ct2 = ct[0..-2] << ct[-1].succ\n    cipher = new_decryptor(\"aes-128-gcm\", key: key, iv: iv, auth_tag: tag, auth_data: aad)\n    cipher.update(ct2)\n    assert_raise(OpenSSL::Cipher::AuthTagError) { cipher.final }\n  end\n\n  def test_aes_gcm_variable_iv_len\n    # GCM spec Appendix B Test Case 5\n    key = [\"feffe9928665731c6d6a8f9467308308\"].pack(\"H*\")\n    iv  = [\"cafebabefacedbad\"].pack(\"H*\")\n    aad = [\"feedfacedeadbeeffeedfacedeadbeef\" \\\n           \"abaddad2\"].pack(\"H*\")\n    pt =  [\"d9313225f88406e5a55909c5aff5269a\" \\\n           \"86a7a9531534f7da2e4c303d8a318a72\" \\\n           \"1c3c0c95956809532fcf0e2449a6b525\" \\\n           \"b16aedf5aa0de657ba637b39\"].pack(\"H*\")\n    ct =  [\"61353b4c2806934a777ff51fa22a4755\" \\\n           \"699b2a714fcdc6f83766e5f97b6c7423\" \\\n           \"73806900e49f24b22b097544d4896b42\" \\\n           \"4989b5e1ebac0f07c23f4598\"].pack(\"H*\")\n    tag = [\"3612d2e79e3b0785561be14aaca2fccb\"].pack(\"H*\")\n\n    cipher = new_encryptor(\"aes-128-gcm\", key: key, iv_len: 8, iv: iv, auth_data: aad)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    assert_equal tag, cipher.auth_tag\n    cipher = new_decryptor(\"aes-128-gcm\", key: key, iv_len: 8, iv: iv, auth_tag: tag, auth_data: aad)\n    assert_equal pt, cipher.update(ct) << cipher.final\n  end\n\n  def test_aes_ocb_tag_len\n    # AES-128-OCB is not FIPS-approved.\n    omit_on_fips\n\n    # RFC 7253 Appendix A; the second sample\n    key = [\"000102030405060708090A0B0C0D0E0F\"].pack(\"H*\")\n    iv  = [\"BBAA99887766554433221101\"].pack(\"H*\")\n    aad = [\"0001020304050607\"].pack(\"H*\")\n    pt =  [\"0001020304050607\"].pack(\"H*\")\n    ct =  [\"6820B3657B6F615A\"].pack(\"H*\")\n    tag = [\"5725BDA0D3B4EB3A257C9AF1F8F03009\"].pack(\"H*\")\n\n    cipher = new_encryptor(\"aes-128-ocb\", key: key, iv: iv, auth_data: aad)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    assert_equal tag, cipher.auth_tag\n    cipher = new_decryptor(\"aes-128-ocb\", key: key, iv: iv, auth_tag: tag, auth_data: aad)\n    assert_equal pt, cipher.update(ct) << cipher.final\n\n    # RFC 7253 Appendix A; with 96 bits tag length\n    key = [\"0F0E0D0C0B0A09080706050403020100\"].pack(\"H*\")\n    iv  = [\"BBAA9988776655443322110D\"].pack(\"H*\")\n    aad = [\"000102030405060708090A0B0C0D0E0F1011121314151617\" \\\n           \"18191A1B1C1D1E1F2021222324252627\"].pack(\"H*\")\n    pt =  [\"000102030405060708090A0B0C0D0E0F1011121314151617\" \\\n           \"18191A1B1C1D1E1F2021222324252627\"].pack(\"H*\")\n    ct =  [\"1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1\" \\\n           \"A0124B0A55BAE884ED93481529C76B6A\"].pack(\"H*\")\n    tag = [\"D0C515F4D1CDD4FDAC4F02AA\"].pack(\"H*\")\n\n    cipher = new_encryptor(\"aes-128-ocb\", auth_tag_len: 12, key: key, iv: iv, auth_data: aad)\n    assert_equal ct, cipher.update(pt) << cipher.final\n    assert_equal tag, cipher.auth_tag\n    cipher = new_decryptor(\"aes-128-ocb\", auth_tag_len: 12, key: key, iv: iv, auth_tag: tag, auth_data: aad)\n    assert_equal pt, cipher.update(ct) << cipher.final\n\n  end if has_cipher?(\"aes-128-ocb\")\n\n  def test_aes_gcm_siv\n    # AES-128-GCM-SIV is not FIPS-approved.\n    omit_on_fips\n\n    # RFC 8452 Appendix C.1., 8th example\n    key = [\"01000000000000000000000000000000\"].pack(\"H*\")\n    iv  = [\"030000000000000000000000\"].pack(\"H*\")\n    aad = [\"01\"].pack(\"H*\")\n    pt =  [\"0200000000000000\"].pack(\"H*\")\n    ct =  [\"1e6daba35669f4273b0a1a2560969cdf790d99759abd1508\"].pack(\"H*\")\n    tag = [\"3b0a1a2560969cdf790d99759abd1508\"].pack(\"H*\")\n    ct_without_tag = ct.byteslice(0, ct.bytesize - tag.bytesize)\n\n    cipher = new_encryptor(\"aes-128-gcm-siv\", key: key, iv: iv, auth_data: aad)\n    assert_equal ct_without_tag, cipher.update(pt) << cipher.final\n    assert_equal tag, cipher.auth_tag\n    cipher = new_decryptor(\"aes-128-gcm-siv\", key: key, iv: iv, auth_tag: tag,\n                           auth_data: aad)\n    assert_equal pt, cipher.update(ct_without_tag) << cipher.final\n  end if openssl?(3, 2, 0)\n\n  def test_aes_gcm_key_iv_order_issue\n    pt = \"[ruby/openssl#49]\"\n    cipher = OpenSSL::Cipher.new(\"aes-128-gcm\").encrypt\n    cipher.key = \"x\" * 16\n    cipher.iv = \"a\" * 12\n    ct1 = cipher.update(pt) << cipher.final\n    tag1 = cipher.auth_tag\n\n    cipher = OpenSSL::Cipher.new(\"aes-128-gcm\").encrypt\n    cipher.iv = \"a\" * 12\n    cipher.key = \"x\" * 16\n    ct2 = cipher.update(pt) << cipher.final\n    tag2 = cipher.auth_tag\n\n    assert_equal ct1, ct2\n    assert_equal tag1, tag2\n  end\n\n  def test_aes_keywrap_pad\n    # RFC 5649 Section 6; The second example\n    kek = [\"5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8\"].pack(\"H*\")\n    key = [\"466f7250617369\"].pack(\"H*\")\n    wrap = [\"afbeb0f07dfbf5419200f2ccb50bb24f\"].pack(\"H*\")\n\n    begin\n      cipher = OpenSSL::Cipher.new(\"id-aes192-wrap-pad\").encrypt\n    rescue OpenSSL::Cipher::CipherError\n      omit \"id-aes192-wrap-pad is not supported: #$!\"\n    end\n    cipher.key = kek\n    ct = cipher.update(key) << cipher.final\n    assert_equal wrap, ct\n  end\n\n  def test_non_aead_cipher_set_auth_data\n    assert_raise(OpenSSL::Cipher::CipherError) {\n      cipher = OpenSSL::Cipher.new(\"aes-128-cfb\").encrypt\n      cipher.auth_data = \"123\"\n    }\n  end\n\n  def test_crypt_after_key\n    key = [\"2b7e151628aed2a6abf7158809cf4f3c\"].pack(\"H*\")\n    %w'ecb cbc cfb ctr gcm'.each do |c|\n      cipher = OpenSSL::Cipher.new(\"aes-128-#{c}\")\n      cipher.key = key\n      cipher.encrypt\n      assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(\"\") }\n\n      cipher = OpenSSL::Cipher.new(\"aes-128-#{c}\")\n      cipher.key = key\n      cipher.decrypt\n      assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(\"\") }\n    end\n  end\n\n  private\n\n  def new_encryptor(algo, **kwargs)\n    OpenSSL::Cipher.new(algo).tap do |cipher|\n      cipher.encrypt\n      kwargs.each {|k, v| cipher.send(:\"#{k}=\", v) }\n    end\n  end\n\n  def new_decryptor(algo, **kwargs)\n    OpenSSL::Cipher.new(algo).tap do |cipher|\n      cipher.decrypt\n      kwargs.each {|k, v| cipher.send(:\"#{k}=\", v) }\n    end\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_config.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestConfig < OpenSSL::TestCase\n  def setup\n    super\n    file = Tempfile.open(\"openssl.cnf\")\n    file << <<__EOD__\nHOME = .\n[ ca ]\ndefault_ca = CA_default\n[ CA_default ]\ndir = ./demoCA\ncerts                =                  ./certs\n__EOD__\n    file.close\n    @tmpfile = file\n    @it = OpenSSL::Config.new(file.path)\n  end\n\n  def teardown\n    super\n    @tmpfile.close!\n  end\n\n  def test_constants\n    assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE))\n    config_file = OpenSSL::Config::DEFAULT_CONFIG_FILE\n    pend \"DEFAULT_CONFIG_FILE may return a wrong path on your platforms. [Bug #6830]\" unless File.readable?(config_file)\n    assert_nothing_raised do\n      OpenSSL::Config.load(config_file)\n    end\n  end\n\n  def test_s_parse\n    c = OpenSSL::Config.parse('')\n    assert_equal(\"[ default ]\\n\\n\", c.to_s)\n    c = OpenSSL::Config.parse(@it.to_s)\n    assert_equal(['CA_default', 'ca', 'default'], c.sections.sort)\n    assert_predicate(c, :frozen?)\n  end\n\n  def test_s_parse_format\n    # AWS-LC removed support for parsing $foo variables.\n    return if aws_lc?\n\n    c = OpenSSL::Config.parse(<<__EOC__)\n baz =qx\\t                # \"baz = qx\"\n\nfoo::bar = baz            # shortcut section::key format\n  default::bar = baz      # ditto\na=\\t \\t                   # \"a = \": trailing spaces are ignored\n =b                       # \" = b\": empty key\n =c                       # \" = c\": empty key (override the above line)\n    d=                    # \"c = \": trailing comment is ignored\n\nsq = 'foo''b\\\\'ar'\n    dq =\"foo\"\"''\\\\\"\"\n    dq2 = foo\"\"bar\nesc=a\\\\r\\\\n\\\\b\\\\tb\nfoo\\\\bar = foo\\\\b\\\\\\\\ar\nfoo\\\\bar::foo\\\\bar = baz\n[default1  default2]\\t\\t  # space is allowed in section name\n          fo =b  ar       # space allowed in value\n[emptysection]\n [dollar ]\nfoo=bar\nbar = $(foo)\nbaz = 123$(default::bar)456${foo}798\nqux = ${baz}\nquxx = $qux.$qux\n__EOC__\n    assert_equal(['default', 'default1  default2', 'dollar', 'emptysection', 'foo', 'foo\\\\bar'], c.sections.sort)\n    assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\\\bar', 'sq'], c['default'].keys.sort)\n    assert_equal('c', c['default'][''])\n    assert_equal('', c['default']['a'])\n    assert_equal('qx', c['default']['baz'])\n    assert_equal('', c['default']['d'])\n    assert_equal('baz', c['default']['bar'])\n    assert_equal(\"foob'ar\", c['default']['sq'])\n    assert_equal(\"foo''\\\"\", c['default']['dq'])\n    assert_equal(\"foobar\", c['default']['dq2'])\n    assert_equal(\"a\\r\\n\\b\\tb\", c['default']['esc'])\n    assert_equal(\"foo\\b\\\\ar\", c['default']['foo\\\\bar'])\n    assert_equal('baz', c['foo']['bar'])\n    assert_equal('baz', c['foo\\\\bar']['foo\\\\bar'])\n    assert_equal('b  ar', c['default1  default2']['fo'])\n\n    # dollar\n    assert_equal('bar', c['dollar']['foo'])\n    assert_equal('bar', c['dollar']['bar'])\n    assert_equal('123baz456bar798', c['dollar']['baz'])\n    assert_equal('123baz456bar798', c['dollar']['qux'])\n    assert_equal('123baz456bar798.123baz456bar798', c['dollar']['quxx'])\n\n    assert_raise_with_message(OpenSSL::ConfigError, /error in line 1: variable has no value/) do\n      OpenSSL::Config.parse(\"foo = $bar\")\n    end\n\n    assert_raise_with_message(OpenSSL::ConfigError, /error in line 1: no close brace/) do\n      OpenSSL::Config.parse(\"foo = $(bar\")\n    end\n\n    assert_raise_with_message(OpenSSL::ConfigError, /error in line 1: missing equal sign/) do\n      OpenSSL::Config.parse(\"f o =b  ar      # no space in key\")\n    end\n\n    assert_raise_with_message(OpenSSL::ConfigError, /error in line 7: missing close square bracket/) do\n      OpenSSL::Config.parse(<<__EOC__)\n# comment 1               # comments\n\n#\n # comment 2\n\\t#comment 3\n  [second    ]\\t\n[third                    # section not terminated\n__EOC__\n    end\n  end\n\n  def test_s_parse_include\n    if !openssl?(1, 1, 1, 2)\n      # OpenSSL < 1.1.1 parses .include directive as a normal assignment\n      pend \".include directive is not supported\"\n    end\n\n    in_tmpdir(\"ossl-config-include-test\") do |dir|\n      Dir.mkdir(\"child\")\n      File.write(\"child/a.conf\", <<~__EOC__)\n        [default]\n        file-a = a.conf\n        [sec-a]\n        a = 123\n      __EOC__\n      File.write(\"child/b.cnf\", <<~__EOC__)\n        [default]\n        file-b = b.cnf\n        [sec-b]\n        b = 123\n      __EOC__\n      File.write(\"include-child.conf\", <<~__EOC__)\n        key_outside_section = value_a\n        .include child\n      __EOC__\n\n      include_file = <<~__EOC__\n        [default]\n        file-main = unnamed\n        [sec-main]\n        main = 123\n        .include = include-child.conf\n      __EOC__\n\n      # Include a file by relative path\n      c1 = OpenSSL::Config.parse(include_file)\n      assert_equal([\"default\", \"sec-a\", \"sec-b\", \"sec-main\"], c1.sections.sort)\n      assert_equal([\"file-a\", \"file-b\", \"file-main\"], c1[\"default\"].keys.sort)\n      assert_equal({\"a\" => \"123\"}, c1[\"sec-a\"])\n      assert_equal({\"b\" => \"123\"}, c1[\"sec-b\"])\n      assert_equal({\"main\" => \"123\", \"key_outside_section\" => \"value_a\"}, c1[\"sec-main\"])\n\n      # Relative paths are from the working directory\n      # Inclusion fails, but the error is ignored silently\n      c2 = Dir.chdir(\"child\") { OpenSSL::Config.parse(include_file) }\n      assert_equal([\"default\", \"sec-main\"], c2.sections.sort)\n    end\n  end\n\n  def test_s_load\n    # alias of new\n    c = OpenSSL::Config.load\n    assert_equal(\"\", c.to_s)\n    assert_equal([], c.sections)\n    #\n    Tempfile.create(\"openssl.cnf\") {|file|\n      file.close\n      c = OpenSSL::Config.load(file.path)\n      assert_equal(\"[ default ]\\n\\n\", c.to_s)\n      assert_equal(['default'], c.sections)\n    }\n  end\n\n  def test_s_parse_config\n    ret = OpenSSL::Config.parse_config(@it.to_s)\n    assert_equal(@it.sections.sort, ret.keys.sort)\n    assert_equal(@it[\"default\"], ret[\"default\"])\n  end\n\n  def test_initialize\n    c = OpenSSL::Config.new\n    assert_equal(\"\", c.to_s)\n    assert_equal([], c.sections)\n    assert_predicate(c, :frozen?)\n  end\n\n  def test_initialize_with_empty_file\n    Tempfile.create(\"openssl.cnf\") {|file|\n      file.close\n      c = OpenSSL::Config.new(file.path)\n      assert_equal(\"[ default ]\\n\\n\", c.to_s)\n      assert_equal(['default'], c.sections)\n    }\n  end\n\n  def test_initialize_with_example_file\n    assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)\n  end\n\n  def test_get_value\n    assert_equal('CA_default', @it.get_value('ca', 'default_ca'))\n    assert_equal(nil, @it.get_value('ca', 'no such key'))\n    assert_equal(nil, @it.get_value('no such section', 'no such key'))\n    assert_equal('.', @it.get_value('', 'HOME'))\n    assert_raise(TypeError) do\n      @it.get_value(nil, 'HOME') # not allowed unlike Config#value\n    end\n    unless aws_lc? # AWS-LC does not support the fallback\n      # fallback to 'default' ugly...\n      assert_equal('.', @it.get_value('unknown', 'HOME'))\n    end\n  end\n\n  def test_get_value_ENV\n    # LibreSSL and AWS-LC removed support for NCONF_get_string(conf, \"ENV\", str)\n    return if libressl? || aws_lc?\n\n    key = ENV.keys.first\n    assert_not_nil(key) # make sure we have at least one ENV var.\n    assert_equal(ENV[key], @it.get_value('ENV', key))\n  end\n\n  def test_aref\n    assert_equal({'HOME' => '.'}, @it['default'])\n    assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default'])\n    assert_equal({}, @it['no_such_section'])\n    assert_equal({}, @it[''])\n  end\n\n  def test_sections\n    assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)\n    Tempfile.create(\"openssl.cnf\") { |f|\n      f.write File.read(@tmpfile.path)\n      f.puts \"[ new_section ]\"\n      f.puts \"foo = bar\"\n      f.puts \"[ empty_section ]\"\n      f.close\n\n      c = OpenSSL::Config.new(f.path)\n      assert_equal(['CA_default', 'ca', 'default', 'empty_section', 'new_section'],\n                   c.sections.sort)\n    }\n  end\n\n  def test_each\n    # each returns [section, key, value] array.\n    ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] }\n    assert_equal(4, ary.size)\n    assert_equal('CA_default', ary[0][0])\n    assert_equal('CA_default', ary[1][0])\n    assert_equal([\"ca\", \"default_ca\", \"CA_default\"], ary[2])\n    assert_equal([\"default\", \"HOME\", \".\"], ary[3])\n  end\n\n  def test_to_s\n    c = OpenSSL::Config.parse(\"[empty]\\n\")\n    assert_equal(\"[ default ]\\n\\n[ empty ]\\n\\n\", c.to_s)\n  end\n\n  def test_inspect\n    assert_match(/#<OpenSSL::Config sections=\\[.*\\]>/, @it.inspect)\n  end\n\n  def test_dup\n    assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)\n    c1 = @it.dup\n    assert_predicate(c1, :frozen?)\n    assert_equal(@it.sections.sort, c1.sections.sort)\n    c2 = @it.clone\n    assert_predicate(c2, :frozen?)\n    assert_equal(@it.sections.sort, c2.sections.sort)\n  end\n\n  if respond_to?(:ractor)\n    ractor\n    def test_ractor\n      assert(Ractor.shareable?(@it))\n      assert(Ractor.shareable?(OpenSSL::Config.parse(\"[empty]\\n\")))\n      assert(Ractor.shareable?(OpenSSL::Config::DEFAULT_CONFIG_FILE))\n    end\n  end\n\n  private\n\n  def in_tmpdir(*args)\n    Dir.mktmpdir(*args) do |dir|\n      dir = File.realpath(dir)\n      Dir.chdir(dir) do\n        yield dir\n      end\n    end\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_digest.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestDigest < OpenSSL::TestCase\n  def setup\n    super\n    @d1 = OpenSSL::Digest.new(\"SHA256\")\n    @d2 = OpenSSL::Digest::SHA256.new\n  end\n\n  def test_initialize\n    assert_raise(OpenSSL::Digest::DigestError) {\n      OpenSSL::Digest.new(\"no such algorithm\")\n    }\n  end\n\n  def test_digest\n    # SHA256 null value calculated by `echo -n \"\" | sha256sum`\n    null_hex = \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n    null_bin = [null_hex].pack(\"H*\")\n    data = \"DATA\"\n    # SHA256 DATA value calculated by `echo -n \"DATA\" | sha256sum`\n    hex = \"c97c29c7a71b392b437ee03fd17f09bb10b75e879466fc0eb757b2c4a78ac938\"\n    bin = [hex].pack(\"H*\")\n    assert_equal(null_bin, @d1.digest)\n    assert_equal(null_hex, @d1.hexdigest)\n    @d1 << data\n    assert_equal(bin, @d1.digest)\n    assert_equal(hex, @d1.hexdigest)\n    assert_equal(bin, OpenSSL::Digest.digest('SHA256', data))\n    assert_equal(hex, OpenSSL::Digest.hexdigest('SHA256', data))\n  end\n\n  def test_eql\n    assert(@d1 == @d2, \"==\")\n    d = @d1.clone\n    assert(d == @d1, \"clone\")\n  end\n\n  def test_info\n    assert_equal(\"SHA256\", @d1.name, \"name\")\n    assert_equal(\"SHA256\", @d2.name, \"name\")\n    assert_equal(32, @d1.size, \"size\")\n  end\n\n  def test_dup\n    @d1.update(\"DATA\")\n    assert_equal(@d1.name, @d1.dup.name, \"dup\")\n    assert_equal(@d1.name, @d1.clone.name, \"clone\")\n    assert_equal(@d1.digest, @d1.clone.digest, \"clone .digest\")\n  end\n\n  def test_reset\n    @d1.update(\"DATA\")\n    dig1 = @d1.digest\n    @d1.reset\n    @d1.update(\"DATA\")\n    dig2 = @d1.digest\n    assert_equal(dig1, dig2, \"reset\")\n  end\n\n  def test_digest_constants\n    non_fips_names = %w{MD5}\n    names = %w{SHA1 SHA224 SHA256 SHA384 SHA512}\n    names = non_fips_names + names unless OpenSSL.fips_mode\n    names.each do |name|\n      assert_not_nil(OpenSSL::Digest.new(name))\n      klass = OpenSSL::Digest.const_get(name.tr('-', '_'))\n      assert_not_nil(klass.new)\n    end\n  end\n\n  def test_digest_by_oid_and_name\n    # SHA256\n    o1 = OpenSSL::Digest.digest(\"SHA256\", \"\")\n    o2 = OpenSSL::Digest.digest(\"sha256\", \"\")\n    assert_equal(o1, o2)\n    o3 = OpenSSL::Digest.digest(\"2.16.840.1.101.3.4.2.1\", \"\")\n    assert_equal(o1, o3)\n\n    # An alias for SHA256 recognized by EVP_get_digestbyname(), but not by\n    # EVP_MD_fetch()\n    o4 = OpenSSL::Digest.digest(\"RSA-SHA256\", \"\")\n    assert_equal(o1, o4)\n  end\n\n  def encode16(str)\n    str.unpack1(\"H*\")\n  end\n\n  def test_sha2\n    sha224_a = \"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5\"\n    sha256_a = \"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb\"\n    sha384_a = \"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31\"\n    sha512_a = \"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75\"\n\n    assert_equal(sha224_a, OpenSSL::Digest.hexdigest('SHA224', \"a\"))\n    assert_equal(sha256_a, OpenSSL::Digest.hexdigest('SHA256', \"a\"))\n    assert_equal(sha384_a, OpenSSL::Digest.hexdigest('SHA384', \"a\"))\n    assert_equal(sha512_a, OpenSSL::Digest.hexdigest('SHA512', \"a\"))\n\n    assert_equal(sha224_a, encode16(OpenSSL::Digest.digest('SHA224', \"a\")))\n    assert_equal(sha256_a, encode16(OpenSSL::Digest.digest('SHA256', \"a\")))\n    assert_equal(sha384_a, encode16(OpenSSL::Digest.digest('SHA384', \"a\")))\n    assert_equal(sha512_a, encode16(OpenSSL::Digest.digest('SHA512', \"a\")))\n  end\n\n  def test_sha512_truncate\n    sha512_224_a = \"d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327\"\n    sha512_256_a = \"455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8\"\n\n    assert_equal(sha512_224_a, OpenSSL::Digest.hexdigest('SHA512-224', \"a\"))\n    assert_equal(sha512_256_a, OpenSSL::Digest.hexdigest('SHA512-256', \"a\"))\n\n    assert_equal(sha512_224_a, encode16(OpenSSL::Digest.digest('SHA512-224', \"a\")))\n    assert_equal(sha512_256_a, encode16(OpenSSL::Digest.digest('SHA512-256', \"a\")))\n  end\n\n  def test_sha3\n    s224 = '6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7'\n    s256 = 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a'\n    s384 = '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004'\n    s512 = 'a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26'\n    assert_equal(s224, OpenSSL::Digest.hexdigest('SHA3-224', \"\"))\n    assert_equal(s256, OpenSSL::Digest.hexdigest('SHA3-256', \"\"))\n    assert_equal(s384, OpenSSL::Digest.hexdigest('SHA3-384', \"\"))\n    assert_equal(s512, OpenSSL::Digest.hexdigest('SHA3-512', \"\"))\n  end\n\n  def test_fetched_evp_md\n    # KECCAK-256 is not FIPS-approved.\n    omit_on_fips\n\n    # Pre-NIST Keccak is an example of a digest algorithm that doesn't have an\n    # NID and requires dynamic allocation of EVP_MD\n    hex = \"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"\n    assert_equal(hex, OpenSSL::Digest.hexdigest(\"KECCAK-256\", \"\"))\n  end if openssl?(3, 2, 0)\n\n  def test_openssl_digest\n    assert_equal OpenSSL::Digest::MD5, OpenSSL::Digest(\"MD5\")\n\n    assert_raise NameError do\n      OpenSSL::Digest(\"no such digest\")\n    end\n  end\n\n  def test_digests\n    digests = OpenSSL::Digest.digests\n    assert_kind_of Array, digests\n    assert_include digests, \"md5\"\n    assert_include digests, \"sha1\"\n    assert_include digests, \"sha256\"\n    assert_include digests, \"sha512\"\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_engine.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL) && defined?(OpenSSL::Engine)\n\nclass OpenSSL::TestEngine < OpenSSL::TestCase\n  def test_engines_free # [ruby-dev:44173]\n    with_openssl <<-'end;'\n      OpenSSL::Engine.load(\"openssl\")\n      OpenSSL::Engine.engines\n      OpenSSL::Engine.engines\n    end;\n  end\n\n  def test_openssl_engine_builtin\n    with_openssl <<-'end;'\n      orig = OpenSSL::Engine.engines\n      pend \"'openssl' is already loaded\" if orig.any? { |e| e.id == \"openssl\" }\n      engine = OpenSSL::Engine.load(\"openssl\")\n      assert_equal(true, engine)\n      assert_equal(1, OpenSSL::Engine.engines.size - orig.size)\n    end;\n  end\n\n  def test_openssl_engine_by_id_string\n    with_openssl <<-'end;'\n      orig = OpenSSL::Engine.engines\n      pend \"'openssl' is already loaded\" if orig.any? { |e| e.id == \"openssl\" }\n      engine = OpenSSL::Engine.by_id(\"openssl\")\n      assert_not_nil(engine)\n      assert_equal(1, OpenSSL::Engine.engines.size - orig.size)\n    end;\n  end\n\n  def test_openssl_engine_id_name_inspect\n    with_openssl <<-'end;'\n      engine = OpenSSL::Engine.by_id(\"openssl\")\n      assert_equal(\"openssl\", engine.id)\n      assert_not_nil(engine.name)\n      assert_not_nil(engine.inspect)\n    end;\n  end\n\n  def test_openssl_engine_digest_sha1\n    with_openssl <<-'end;'\n      engine = OpenSSL::Engine.by_id(\"openssl\")\n      digest = engine.digest(\"SHA1\")\n      assert_not_nil(digest)\n      data = \"test\"\n      assert_equal(OpenSSL::Digest.digest('SHA1', data), digest.digest(data))\n    end;\n  end\n\n  def test_openssl_engine_cipher_rc4\n    begin\n      OpenSSL::Cipher.new(\"rc4\")\n    rescue OpenSSL::Cipher::CipherError\n      pend \"RC4 is not supported\"\n    end\n\n    with_openssl(<<-'end;', ignore_stderr: true)\n      engine = OpenSSL::Engine.by_id(\"openssl\")\n      algo = \"RC4\"\n      data = \"a\" * 1000\n      key = OpenSSL::Random.random_bytes(16)\n\n      cipher = engine.cipher(algo)\n      cipher.encrypt\n      cipher.key = key\n      encrypted = cipher.update(data) + cipher.final\n\n      cipher = OpenSSL::Cipher.new(algo)\n      cipher.decrypt\n      cipher.key = key\n      decrypted = cipher.update(encrypted) + cipher.final\n\n      assert_equal(data, decrypted)\n    end;\n  end\n\n  private\n\n  # this is required because OpenSSL::Engine methods change global state\n  def with_openssl(code, **opts)\n    assert_separately([\"-ropenssl\"], <<~\"end;\", **opts)\n      #{code}\n    end;\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_fips.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestFIPS < OpenSSL::TestCase\n  def test_fips_mode_get_is_true_on_fips_mode_enabled\n    unless ENV[\"TEST_RUBY_OPENSSL_FIPS_ENABLED\"]\n      omit \"Only for FIPS mode environment\"\n    end\n\n    assert_separately([\"-ropenssl\"], <<~\"end;\")\n      assert OpenSSL.fips_mode == true, \".fips_mode should return true on FIPS mode enabled\"\n    end;\n  end\n\n  def test_fips_mode_get_is_false_on_fips_mode_disabled\n    if ENV[\"TEST_RUBY_OPENSSL_FIPS_ENABLED\"]\n      omit \"Only for non-FIPS mode environment\"\n    end\n\n    assert_separately([\"-ropenssl\"], <<~\"end;\")\n      message = \".fips_mode should return false on FIPS mode disabled. \" \\\n                \"If you run the test on FIPS mode, please set \" \\\n                \"TEST_RUBY_OPENSSL_FIPS_ENABLED=true\"\n      assert OpenSSL.fips_mode == false, message\n    end;\n  end\n\n  def test_fips_mode_is_reentrant\n    return if aws_lc? # AWS-LC's FIPS mode is decided at compile time.\n\n    assert_ruby_status([\"-ropenssl\"], <<~\"end;\")\n      OpenSSL.fips_mode = false\n      OpenSSL.fips_mode = false\n    end;\n  end\n\n  def test_fips_mode_get_with_fips_mode_set\n    return if aws_lc? # AWS-LC's FIPS mode is decided at compile time.\n    unless ENV[\"TEST_RUBY_OPENSSL_FIPS_ENABLED\"]\n      omit \"Only for FIPS mode environment\"\n    end\n\n    assert_separately([\"-ropenssl\"], <<~\"end;\")\n      begin\n        OpenSSL.fips_mode = true\n        assert OpenSSL.fips_mode == true, \".fips_mode should return true when .fips_mode=true\"\n\n        OpenSSL.fips_mode = false\n        assert OpenSSL.fips_mode == false, \".fips_mode should return false when .fips_mode=false\"\n      rescue OpenSSL::OpenSSLError\n        pend \"Could not set FIPS mode (OpenSSL::OpenSSLError: \\#$!); skipping\"\n      end\n    end;\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_hmac.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestHMAC < OpenSSL::TestCase\n  def test_hmac\n    # RFC 2202 2. Test Cases for HMAC-MD5\n    hmac = OpenSSL::HMAC.new([\"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\"].pack(\"H*\"), \"MD5\")\n    hmac.update(\"Hi There\")\n    assert_equal [\"9294727a3638bb1c13f48ef8158bfc9d\"].pack(\"H*\"), hmac.digest\n    assert_equal \"9294727a3638bb1c13f48ef8158bfc9d\", hmac.hexdigest\n    assert_equal \"kpRyejY4uxwT9I74FYv8nQ==\", hmac.base64digest\n\n    # RFC 4231 4.2. Test Case 1\n    hmac = OpenSSL::HMAC.new([\"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\"].pack(\"H*\"), \"SHA224\")\n    hmac.update(\"Hi There\")\n    assert_equal [\"896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22\"].pack(\"H*\"), hmac.digest\n    assert_equal \"896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22\", hmac.hexdigest\n    assert_equal \"iW+xEoq73xloMhB81J3zP0e0sRaZErpPU2hLIg==\", hmac.base64digest\n  end\n\n  def test_dup\n    h1 = OpenSSL::HMAC.new(\"KEY\", \"MD5\")\n    h1.update(\"DATA\")\n    h = h1.dup\n    assert_equal(h1.digest, h.digest, \"dup digest\")\n  end\n\n  def test_binary_update\n    data = \"Lücíllé: Bût... yøü sáîd hé wås âlrîght.\\nDr. Físhmån: Yés. Hé's løst hîs léft hånd, sø hé's gøîng tø bé åll rîght\"\n    hmac = OpenSSL::HMAC.new(\"qShkcwN92rsM9nHfdnP4ugcVU2iI7iM/trovs01ZWok\", \"SHA256\")\n    result = hmac.update(data).hexdigest\n    assert_equal \"a13984b929a07912e4e21c5720876a8e150d6f67f854437206e7f86547248396\", result\n  end\n\n  def test_reset_keep_key\n    h1 = OpenSSL::HMAC.new(\"KEY\", \"MD5\")\n    first = h1.update(\"test\").hexdigest\n    h1.reset\n    second = h1.update(\"test\").hexdigest\n    assert_equal first, second\n  end\n\n  def test_eq\n    h1 = OpenSSL::HMAC.new(\"KEY\", \"MD5\")\n    h2 = OpenSSL::HMAC.new(\"KEY\", OpenSSL::Digest.new(\"MD5\"))\n    h3 = OpenSSL::HMAC.new(\"FOO\", \"MD5\")\n\n    assert_equal h1, h2\n    refute_equal h1, h2.digest\n    refute_equal h1, h3\n  end\n\n  def test_singleton_methods\n    # RFC 2202 2. Test Cases for HMAC-MD5\n    key = [\"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\"].pack(\"H*\")\n    digest = OpenSSL::HMAC.digest(\"MD5\", key, \"Hi There\")\n    assert_equal [\"9294727a3638bb1c13f48ef8158bfc9d\"].pack(\"H*\"), digest\n    hexdigest = OpenSSL::HMAC.hexdigest(\"MD5\", key, \"Hi There\")\n    assert_equal \"9294727a3638bb1c13f48ef8158bfc9d\", hexdigest\n    b64digest = OpenSSL::HMAC.base64digest(\"MD5\", key, \"Hi There\")\n    assert_equal \"kpRyejY4uxwT9I74FYv8nQ==\", b64digest\n  end\n\n  def test_zero_length_key\n    # Empty string as the key\n    hexdigest = OpenSSL::HMAC.hexdigest(\"SHA256\", \"\\0\"*32, \"test\")\n    assert_equal \"43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb\", hexdigest\n    hexdigest = OpenSSL::HMAC.hexdigest(\"SHA256\", \"\", \"test\")\n    assert_equal \"43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb\", hexdigest\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_kdf.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestKDF < OpenSSL::TestCase\n  def test_pkcs5_pbkdf2_hmac_compatibility\n    expected = OpenSSL::KDF.pbkdf2_hmac(\"password\", salt: \"salt\", iterations: 1, length: 20, hash: \"sha1\")\n    assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac(\"password\", \"salt\", 1, 20, \"sha1\"))\n    assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1(\"password\", \"salt\", 1, 20))\n  end\n\n  def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20\n    p =\"password\"\n    s = \"salt\"\n    c = 1\n    dk_len = 20\n    raw = %w{ 0c 60 c8 0f 96 1f 0e 71\n              f3 a9 b5 24 af 60 12 06\n              2f e0 37 a6 }\n    expected = [raw.join('')].pack('H*')\n    value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: \"sha1\")\n    assert_equal(expected, value)\n  end\n\n  def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20\n    p =\"password\"\n    s = \"salt\"\n    c = 2\n    dk_len = 20\n    raw = %w{ ea 6c 01 4d c7 2d 6f 8c\n              cd 1e d9 2a ce 1d 41 f0\n              d8 de 89 57 }\n    expected = [raw.join('')].pack('H*')\n    value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: \"sha1\")\n    assert_equal(expected, value)\n  end\n\n  def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20\n    p =\"password\"\n    s = \"salt\"\n    c = 4096\n    dk_len = 20\n    raw = %w{ 4b 00 79 01 b7 65 48 9a\n              be ad 49 d9 26 f7 21 d0\n              65 a4 29 c1 }\n    expected = [raw.join('')].pack('H*')\n    value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: \"sha1\")\n    assert_equal(expected, value)\n  end\n\n# takes too long!\n#  def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20\n#    p =\"password\"\n#    s = \"salt\"\n#    c = 16777216\n#    dk_len = 20\n#    raw = %w{ ee fe 3d 61 cd 4d a4 e4\n#              e9 94 5b 3d 6b a2 15 8c\n#              26 34 e9 84 }\n#    expected = [raw.join('')].pack('H*')\n#    value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: \"sha1\")\n#    assert_equal(expected, value)\n#  end\n\n  def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25\n    p =\"passwordPASSWORDpassword\"\n    s = \"saltSALTsaltSALTsaltSALTsaltSALTsalt\"\n    c = 4096\n    dk_len = 25\n\n    raw = %w{ 3d 2e ec 4f e4 1c 84 9b\n              80 c8 d8 36 62 c0 e4 4a\n              8b 29 1a 96 4c f2 f0 70\n              38 }\n    expected = [raw.join('')].pack('H*')\n    value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: \"sha1\")\n    assert_equal(expected, value)\n  end\n\n  def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16\n    p =\"pass\\0word\"\n    s = \"sa\\0lt\"\n    c = 4096\n    dk_len = 16\n    raw = %w{ 56 fa 6a a7 55 48 09 9d\n              cc 37 d7 f0 34 25 e0 c3 }\n    expected = [raw.join('')].pack('H*')\n    value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: \"sha1\")\n    assert_equal(expected, value)\n  end\n\n  def test_pbkdf2_hmac_sha256_c_20000_len_32\n    #unfortunately no official test vectors available yet for SHA-2\n    p =\"password\"\n    s = OpenSSL::Random.random_bytes(16)\n    c = 20000\n    dk_len = 32\n    value1 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: \"sha256\")\n    value2 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: \"sha256\")\n    assert_equal(value1, value2)\n  end\n\n  def test_scrypt_rfc7914_first\n    pend \"scrypt is not implemented\" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0\n    pass = \"\"\n    salt = \"\"\n    n = 16\n    r = 1\n    p = 1\n    dklen = 64\n    expected = B(%w{ 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97\n                     f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42\n                     fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17\n                     e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 })\n    assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen))\n  end\n\n  def test_scrypt_rfc7914_second\n    pend \"scrypt is not implemented\" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0\n    pass = \"password\"\n    salt = \"NaCl\"\n    n = 1024\n    r = 8\n    p = 16\n    dklen = 64\n    expected = B(%w{ fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe\n                     7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62\n                     2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da\n                     c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 })\n    assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen))\n  end\n\n  def test_hkdf_rfc5869_test_case_1\n    hash = \"sha256\"\n    ikm = B(\"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\")\n    salt = B(\"000102030405060708090a0b0c\")\n    info = B(\"f0f1f2f3f4f5f6f7f8f9\")\n    l = 42\n\n    okm = B(\"3cb25f25faacd57a90434f64d0362f2a\" \\\n            \"2d2d0a90cf1a5a4c5db02d56ecc4c5bf\" \\\n            \"34007208d5b887185865\")\n    assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))\n  end\n\n  def test_hkdf_rfc5869_test_case_3\n    hash = \"sha256\"\n    ikm = B(\"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b\")\n    salt = B(\"\")\n    info = B(\"\")\n    l = 42\n\n    okm = B(\"8da4e775a563c18f715f802a063c5a31\" \\\n            \"b8a11f5c5ee1879ec3454e5f3c738d2d\" \\\n            \"9d201395faa4b61a96c8\")\n    assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))\n  end\n\n  def test_hkdf_rfc5869_test_case_4\n    hash = \"sha1\"\n    ikm = B(\"0b0b0b0b0b0b0b0b0b0b0b\")\n    salt = B(\"000102030405060708090a0b0c\")\n    info = B(\"f0f1f2f3f4f5f6f7f8f9\")\n    l = 42\n\n    okm = B(\"085a01ea1b10f36933068b56efa5ad81\" \\\n            \"a4f14b822f5b091568a9cdd4f155fda2\" \\\n            \"c22e422478d305f3f896\")\n    assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash))\n  end\n\n  private\n\n  def B(ary)\n    [Array(ary).join].pack(\"H*\")\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_ns_spki.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestNSSPI < OpenSSL::TestCase\n  def setup\n    super\n    # This request data is adopt from the specification of\n    # \"Netscape Extensions for User Key Generation\".\n    # -- http://wp.netscape.com/eng/security/comm4-keygen.html\n    @b64 = +\"MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue+PtwBRE6XfV\"\n    @b64 << \"WtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID\"\n    @b64 << \"AQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n/S\"\n    @b64 << \"r/7iJNroWlSzSMtTiQTEB+ADWHGj9u1xrUrOilq/o2cuQxIfZcNZkYAkWP4DubqW\"\n    @b64 << \"i0//rgBvmco=\"\n  end\n\n  def test_build_data\n    key1 = Fixtures.pkey(\"rsa-1\")\n    key2 = Fixtures.pkey(\"rsa-2\")\n    spki = OpenSSL::Netscape::SPKI.new\n    spki.challenge = \"RandomString\"\n    spki.public_key = key1.public_key\n    spki.sign(key1, OpenSSL::Digest.new('SHA256'))\n    assert(spki.verify(spki.public_key))\n    assert(spki.verify(key1.public_key))\n    assert(!spki.verify(key2.public_key))\n\n    der = spki.to_der\n    spki = OpenSSL::Netscape::SPKI.new(der)\n    assert_equal(\"RandomString\", spki.challenge)\n    assert_equal(key1.public_key.to_der, spki.public_key.to_der)\n    assert(spki.verify(spki.public_key))\n    assert_not_nil(spki.to_text)\n  end\n\n  def test_decode_data\n    spki = OpenSSL::Netscape::SPKI.new(@b64)\n    assert_equal(@b64, spki.to_pem)\n    assert_equal(@b64.unpack1(\"m\"), spki.to_der)\n    assert_equal(\"MozillaIsMyFriend\", spki.challenge)\n    assert_equal(OpenSSL::PKey::RSA, spki.public_key.class)\n\n    spki = OpenSSL::Netscape::SPKI.new(@b64.unpack1(\"m\"))\n    assert_equal(@b64, spki.to_pem)\n    assert_equal(@b64.unpack1(\"m\"), spki.to_der)\n    assert_equal(\"MozillaIsMyFriend\", spki.challenge)\n    assert_equal(OpenSSL::PKey::RSA, spki.public_key.class)\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_ocsp.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestOCSP < OpenSSL::TestCase\n  def setup\n    super\n    # @ca_cert\n    #   |\n    # @cert\n    #   |----------|\n    # @cert2   @ocsp_cert\n\n    ca_subj = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=TestCA\")\n    @ca_key = Fixtures.pkey(\"rsa-1\")\n    ca_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign,keyCertSign\", true],\n    ]\n    @ca_cert = OpenSSL::TestUtils.issue_cert(\n      ca_subj, @ca_key, 1, ca_exts, nil, nil)\n\n    cert_subj = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=TestCA2\")\n    @cert_key = Fixtures.pkey(\"rsa-2\")\n    cert_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign,keyCertSign\", true],\n    ]\n    @cert = OpenSSL::TestUtils.issue_cert(\n      cert_subj, @cert_key, 5, cert_exts, @ca_cert, @ca_key)\n\n    cert2_subj = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=TestCert\")\n    @cert2_key = Fixtures.pkey(\"rsa-3\")\n    cert2_exts = [\n    ]\n    @cert2 = OpenSSL::TestUtils.issue_cert(\n      cert2_subj, @cert2_key, 10, cert2_exts, @cert, @cert_key)\n\n    ocsp_subj = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=TestCAOCSP\")\n    @ocsp_key = Fixtures.pkey(\"p256\")\n    ocsp_exts = [\n      [\"extendedKeyUsage\", \"OCSPSigning\", true],\n    ]\n    @ocsp_cert = OpenSSL::TestUtils.issue_cert(\n       ocsp_subj, @ocsp_key, 100, ocsp_exts, @cert, @cert_key)\n  end\n\n  def test_new_certificate_id\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)\n    assert_kind_of OpenSSL::OCSP::CertificateId, cid\n    assert_equal @cert.serial, cid.serial\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA256'))\n    assert_kind_of OpenSSL::OCSP::CertificateId, cid\n    assert_equal @cert.serial, cid.serial\n  end\n\n  def test_certificate_id_issuer_name_hash\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)\n    assert_equal OpenSSL::Digest.hexdigest('SHA1', @cert.issuer.to_der), cid.issuer_name_hash\n    assert_equal \"d91f736ac4dc3242f0fb9b77a3149bd83c5c43d0\", cid.issuer_name_hash\n  end\n\n  def test_certificate_id_issuer_key_hash\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)\n    # content of subjectPublicKey (bit string) in SubjectPublicKeyInfo\n    spki = OpenSSL::ASN1.decode(@ca_key.public_to_der)\n    assert_equal OpenSSL::Digest.hexdigest(\"SHA1\", spki.value[1].value),\n      cid.issuer_key_hash\n  end\n\n  def test_certificate_id_hash_algorithm\n    cid_sha1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    cid_sha256 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA256'))\n    assert_equal \"sha1\", cid_sha1.hash_algorithm\n    assert_equal \"sha256\", cid_sha256.hash_algorithm\n  end\n\n  def test_certificate_id_der\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)\n    der = cid.to_der\n    asn1 = OpenSSL::ASN1.decode(der)\n    # hash algorithm defaults to SHA-1\n    assert_equal OpenSSL::ASN1.ObjectId(\"SHA1\").to_der, asn1.value[0].value[0].to_der\n    assert_equal [cid.issuer_name_hash].pack(\"H*\"), asn1.value[1].value\n    assert_equal [cid.issuer_key_hash].pack(\"H*\"), asn1.value[2].value\n    assert_equal @cert.serial, asn1.value[3].value\n    assert_equal der, OpenSSL::OCSP::CertificateId.new(der).to_der\n    assert_equal der, OpenSSL::OCSP::CertificateId.new(asn1).to_der\n  end\n\n  def test_certificate_id_dup\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)\n    assert_equal cid.to_der, cid.dup.to_der\n  end\n\n  def test_request_der\n    request = OpenSSL::OCSP::Request.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    request.add_certid(cid)\n    request.sign(@cert, @cert_key, [@ca_cert], 0)\n    asn1 = OpenSSL::ASN1.decode(request.to_der)\n    assert_equal cid.to_der, asn1.value[0].value.find { |a| a.tag_class == :UNIVERSAL }.value[0].value[0].to_der\n    assert_equal OpenSSL::ASN1.ObjectId(\"sha256WithRSAEncryption\").to_der, asn1.value[1].value[0].value[0].value[0].to_der\n    assert_equal @cert.to_der, asn1.value[1].value[0].value[2].value[0].value[0].to_der\n    assert_equal @ca_cert.to_der, asn1.value[1].value[0].value[2].value[0].value[1].to_der\n    assert_equal asn1.to_der, OpenSSL::OCSP::Request.new(asn1.to_der).to_der\n  end\n\n  def test_request_sign_verify\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)\n    store = OpenSSL::X509::Store.new.add_cert(@ca_cert)\n\n    # with signer cert\n    req = OpenSSL::OCSP::Request.new.add_certid(cid)\n    req.sign(@cert, @cert_key, [])\n    assert_equal true, req.verify([], store)\n\n    # without signer cert\n    req = OpenSSL::OCSP::Request.new.add_certid(cid)\n    req.sign(@cert, @cert_key, nil)\n    assert_equal false, req.verify([@cert2], store)\n    assert_equal false, req.verify([], store) # no signer\n    assert_equal false, req.verify([], store, OpenSSL::OCSP::NOVERIFY)\n\n    assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN)\n    ret = req.verify([@cert], store)\n    assert_equal true, ret\n\n    # not signed\n    req = OpenSSL::OCSP::Request.new.add_certid(cid)\n    assert_equal false, req.verify([], store)\n  end\n\n  def test_request_is_signed\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)\n    req = OpenSSL::OCSP::Request.new\n    req.add_certid(cid)\n    assert_equal false, req.signed?\n    assert_equal false, OpenSSL::OCSP::Request.new(req.to_der).signed?\n    req.sign(@cert, @cert_key, [])\n    assert_equal true, req.signed?\n    assert_equal true, OpenSSL::OCSP::Request.new(req.to_der).signed?\n  end\n\n  def test_request_nonce\n    req0 = OpenSSL::OCSP::Request.new\n    req1 = OpenSSL::OCSP::Request.new.add_nonce(\"NONCE\")\n    req2 = OpenSSL::OCSP::Request.new.add_nonce(\"ABCDE\")\n    bres = OpenSSL::OCSP::BasicResponse.new\n    assert_equal 2, req0.check_nonce(bres)\n    bres.copy_nonce(req1)\n    assert_equal 3, req0.check_nonce(bres)\n    assert_equal 1, req1.check_nonce(bres)\n    bres.add_nonce(\"NONCE\")\n    assert_equal 1, req1.check_nonce(bres)\n    assert_equal 0, req2.check_nonce(bres)\n  end\n\n  def test_request_dup\n    request = OpenSSL::OCSP::Request.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    request.add_certid(cid)\n    assert_equal request.to_der, request.dup.to_der\n  end\n\n  def test_basic_response_der\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])\n    bres.add_nonce(\"NONCE\")\n    bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0)\n    der = bres.to_der\n    asn1 = OpenSSL::ASN1.decode(der)\n    assert_equal OpenSSL::ASN1.Sequence([@ocsp_cert, @ca_cert]).to_der, asn1.value[3].value[0].to_der\n    assert_equal der, OpenSSL::OCSP::BasicResponse.new(der).to_der\n  rescue TypeError\n    if /GENERALIZEDTIME/ =~ $!.message\n      pend \"OCSP_basic_sign() is broken\"\n    else\n      raise\n    end\n  end\n\n  def test_basic_response_sign_verify\n    store = OpenSSL::X509::Store.new.add_cert(@ca_cert)\n\n    # signed by CA\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, \"SHA256\")\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, -400, -300, 500, [])\n    bres.sign(@ca_cert, @ca_key, nil, 0, \"SHA256\")\n    assert_equal false, bres.verify([], store) # signer not found\n    assert_equal true, bres.verify([@ca_cert], store)\n    bres.sign(@ca_cert, @ca_key, [], 0, \"SHA256\")\n    assert_equal true, bres.verify([], store)\n\n    # signed by OCSP signer\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert2, @cert)\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, -400, -300, 500, [])\n    bres.sign(@ocsp_cert, @ocsp_key, [@cert])\n    assert_equal true, bres.verify([], store)\n    assert_equal false, bres.verify([], store, OpenSSL::OCSP::NOCHAIN)\n    # OpenSSL had a bug on this; test that our workaround works\n    bres.sign(@ocsp_cert, @ocsp_key, [])\n    assert_equal true, bres.verify([@cert], store)\n  end\n\n  def test_basic_response_dup\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])\n    bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0)\n    assert_equal bres.to_der, bres.dup.to_der\n  end\n\n  def test_basic_response_status_good\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, nil)\n    bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert])\n\n    statuses = bres.status\n    assert_equal 1, statuses.size\n    status = statuses[0]\n    assert_equal cid.to_der, status[0].to_der\n    assert_equal OpenSSL::OCSP::V_CERTSTATUS_GOOD, status[1]\n    assert_nil status[3] # revtime should be nil for GOOD status\n  end\n\n  def test_basic_response_status_revoked\n    bres = OpenSSL::OCSP::BasicResponse.new\n    now = Time.at(Time.now.to_i)\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_REVOKED,\n                    OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, now - 400, -300, nil, nil)\n    bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert])\n\n    statuses = bres.status\n    assert_equal 1, statuses.size\n    status = statuses[0]\n    assert_equal OpenSSL::OCSP::V_CERTSTATUS_REVOKED, status[1]\n    assert_equal now - 400, status[3] # revtime should be the revocation time\n  end\n\n  def test_basic_response_response_operations\n    bres = OpenSSL::OCSP::BasicResponse.new\n    now = Time.at(Time.now.to_i)\n    cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    cid2 = OpenSSL::OCSP::CertificateId.new(@ocsp_cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    cid3 = OpenSSL::OCSP::CertificateId.new(@ca_cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, now - 400, -300, nil, nil)\n    bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, [])\n\n    assert_equal 2, bres.responses.size\n    single = bres.responses.first\n    assert_equal cid1.to_der, single.certid.to_der\n    assert_equal OpenSSL::OCSP::V_CERTSTATUS_REVOKED, single.cert_status\n    assert_equal OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, single.revocation_reason\n    assert_equal now - 400, single.revocation_time\n    assert_in_delta (now - 300), single.this_update, 1\n    assert_equal nil, single.next_update\n    assert_equal [], single.extensions\n\n    assert_equal cid2.to_der, bres.find_response(cid2).certid.to_der\n    assert_equal nil, bres.find_response(cid3)\n  end\n\n  def test_single_response_der\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert)\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, -300, 500, nil)\n    single = bres.responses[0]\n    der = single.to_der\n    asn1 = OpenSSL::ASN1.decode(der)\n    assert_equal :CONTEXT_SPECIFIC, asn1.value[1].tag_class\n    assert_equal 0, asn1.value[1].tag # good\n    assert_equal der, OpenSSL::OCSP::SingleResponse.new(der).to_der\n  end\n\n  def test_single_response_check_validity\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid1 = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    cid2 = OpenSSL::OCSP::CertificateId.new(@ocsp_cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    bres.add_status(cid1, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, -50, [])\n    bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, [])\n    bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, Time.now + 100, nil, nil)\n\n    single1 = bres.responses[0]\n    assert_equal false, single1.check_validity\n    assert_equal false, single1.check_validity(30)\n    assert_equal true, single1.check_validity(60)\n    single2 = bres.responses[1]\n    assert_equal true, single2.check_validity\n    assert_equal true, single2.check_validity(0, 500)\n    assert_equal false, single2.check_validity(0, 200)\n    single3 = bres.responses[2]\n    assert_equal false, single3.check_validity\n  end\n\n  def test_response\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])\n    bres.sign(@ocsp_cert, @ocsp_key, [])\n    res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres)\n\n    assert_equal bres.to_der, res.basic.to_der\n    assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, res.status\n  end\n\n  def test_response_der\n    bres = OpenSSL::OCSP::BasicResponse.new\n    cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert, OpenSSL::Digest.new('SHA1'))\n    bres.add_status(cid, OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, nil, -300, 500, [])\n    bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0)\n    res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres)\n    der = res.to_der\n    asn1 = OpenSSL::ASN1.decode(der)\n    assert_equal OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, asn1.value[0].value\n    assert_equal OpenSSL::ASN1.ObjectId(\"basicOCSPResponse\").to_der, asn1.value[1].value[0].value[0].to_der\n    assert_equal bres.to_der, asn1.value[1].value[0].value[1].value\n    assert_equal der, OpenSSL::OCSP::Response.new(der).to_der\n  end\n\n  def test_response_dup\n    bres = OpenSSL::OCSP::BasicResponse.new\n    bres.sign(@ocsp_cert, @ocsp_key, [@ca_cert], 0)\n    res = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, bres)\n    assert_equal res.to_der, res.dup.to_der\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_ossl.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestOSSL < OpenSSL::TestCase\n  def test_fixed_length_secure_compare\n    assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare(\"aaa\", \"a\") }\n    assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare(\"aaa\", \"aa\") }\n\n    assert_true(OpenSSL.fixed_length_secure_compare(\"aaa\", \"aaa\"))\n    assert_true(OpenSSL.fixed_length_secure_compare(\n      OpenSSL::Digest.digest('SHA256', \"aaa\"), OpenSSL::Digest::SHA256.digest(\"aaa\")\n    ))\n\n    assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare(\"aaa\", \"aaaa\") }\n    assert_false(OpenSSL.fixed_length_secure_compare(\"aaa\", \"baa\"))\n    assert_false(OpenSSL.fixed_length_secure_compare(\"aaa\", \"aba\"))\n    assert_false(OpenSSL.fixed_length_secure_compare(\"aaa\", \"aab\"))\n    assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare(\"aaa\", \"aaab\") }\n    assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare(\"aaa\", \"b\") }\n    assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare(\"aaa\", \"bb\") }\n    assert_false(OpenSSL.fixed_length_secure_compare(\"aaa\", \"bbb\"))\n    assert_raise(ArgumentError) { OpenSSL.fixed_length_secure_compare(\"aaa\", \"bbbb\") }\n  end\n\n  def test_fixed_length_secure_compare_uaf\n    str1 = \"A\" * 1000000\n    evil_obj = Object.new\n    evil_obj.define_singleton_method(:to_str) do\n      str1.replace(\"C\" * 1000000)\n      \"B\" * 1000000\n    end\n    assert_false(OpenSSL.fixed_length_secure_compare(str1, evil_obj))\n  end\n\n  def test_secure_compare\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"a\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"aa\"))\n\n    assert_true(OpenSSL.secure_compare(\"aaa\", \"aaa\"))\n\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"aaaa\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"baa\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"aba\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"aab\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"aaab\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"b\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"bb\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"bbb\"))\n    assert_false(OpenSSL.secure_compare(\"aaa\", \"bbbb\"))\n  end\n\n  def test_memcmp_timing\n    # Ensure using fixed_length_secure_compare takes almost exactly the same amount of time to compare two different strings.\n    # Regular string comparison will short-circuit on the first non-matching character, failing this test.\n    # NOTE: this test may be susceptible to noise if the system running the tests is otherwise under load.\n    a = \"x\" * 512_000\n    b = \"#{a}y\"\n    c = \"y#{a}\"\n    a = \"#{a}x\"\n\n    a_b_time = a_c_time = 0\n    100.times do\n      t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)\n      100.times { OpenSSL.fixed_length_secure_compare(a, b) }\n      t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)\n      100.times { OpenSSL.fixed_length_secure_compare(a, c) }\n      t3 = Process.clock_gettime(Process::CLOCK_MONOTONIC)\n\n      a_b_time += t2 - t1\n      a_c_time += t3 - t2\n    end\n    assert_operator(a_b_time, :<, a_c_time * 10, \"fixed_length_secure_compare timing test failed\")\n    assert_operator(a_c_time, :<, a_b_time * 10, \"fixed_length_secure_compare timing test failed\")\n  end if ENV[\"OSSL_TEST_ALL\"] == \"1\"\n\n  def test_error_data\n    # X509V3_EXT_nconf_nid() called from\n    # OpenSSL::X509::ExtensionFactory#create_ext is a function that uses\n    # ERR_raise_data() to append additional information about the error.\n    #\n    # The generated message should look like:\n    #     \"subjectAltName = IP:not.a.valid.ip.address: bad ip address (value=not.a.valid.ip.address)\"\n    #     \"subjectAltName = IP:not.a.valid.ip.address: error in extension (name=subjectAltName, value=IP:not.a.valid.ip.address)\"\n    #\n    # The string inside parentheses is the ERR_TXT_STRING data, and is appended\n    # by ossl_make_error(), so we check it here.\n    ef = OpenSSL::X509::ExtensionFactory.new\n    e = assert_raise(OpenSSL::X509::ExtensionError) {\n      ef.create_ext(\"subjectAltName\", \"IP:not.a.valid.ip.address\")\n    }\n    assert_match(/not.a.valid.ip.address\\)\\z/, e.message)\n\n    # We currently craft the strings based on ERR_error_string()'s style:\n    #     error:<error code in hex>:<library>:<function>:<reason> (data)\n    assert_instance_of(Array, e.errors)\n    assert_match(/\\Aerror:.*not.a.valid.ip.address\\)\\z/, e.errors.last)\n    assert_include(e.detailed_message, \"not.a.valid.ip.address\")\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_pair.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\nrequire_relative 'ut_eof'\n\nif defined?(OpenSSL::SSL)\n\nmodule OpenSSL::SSLPairM\n  def setup\n    svr_dn = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=localhost\")\n    ee_exts = [\n      [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n    ]\n    @svr_key = OpenSSL::TestUtils::Fixtures.pkey(\"rsa-1\")\n    @svr_cert = issue_cert(svr_dn, @svr_key, 1, ee_exts, nil, nil)\n  end\n\n  def ssl_pair\n    host = \"127.0.0.1\"\n    tcps = create_tcp_server(host, 0)\n    port = tcps.connect_address.ip_port\n\n    th = Thread.new {\n      sctx = OpenSSL::SSL::SSLContext.new\n      sctx.cert = @svr_cert\n      sctx.key = @svr_key\n      sctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION\n      ssls = OpenSSL::SSL::SSLServer.new(tcps, sctx)\n      ns = ssls.accept\n      ssls.close\n      ns\n    }\n\n    tcpc = create_tcp_client(host, port)\n    c = OpenSSL::SSL::SSLSocket.new(tcpc)\n    c.connect\n    s = th.value\n\n    yield c, s\n  ensure\n    tcpc&.close\n    tcps&.close\n    s&.close\n  end\nend\n\nmodule OpenSSL::SSLPair\n  include OpenSSL::SSLPairM\n\n  def create_tcp_server(host, port)\n    TCPServer.new(host, port)\n  end\n\n  def create_tcp_client(host, port)\n    TCPSocket.new(host, port)\n  end\nend\n\nmodule OpenSSL::SSLPairLowlevelSocket\n  include OpenSSL::SSLPairM\n\n  def create_tcp_server(host, port)\n    Addrinfo.tcp(host, port).listen\n  end\n\n  def create_tcp_client(host, port)\n    Addrinfo.tcp(host, port).connect\n  end\nend\n\nmodule OpenSSL::TestEOF1M\n  def open_file(content)\n    ssl_pair { |s1, s2|\n      begin\n        th = Thread.new { s2 << content; s2.close }\n        yield s1\n      ensure\n        th&.join\n      end\n    }\n  end\nend\n\nmodule OpenSSL::TestEOF2M\n  def open_file(content)\n    ssl_pair { |s1, s2|\n      begin\n        th = Thread.new { s1 << content; s1.close }\n        yield s2\n      ensure\n        th&.join\n      end\n    }\n  end\nend\n\nmodule OpenSSL::TestPairM\n  def test_getc\n    ssl_pair {|s1, s2|\n      s1 << \"a\"\n      assert_equal(?a, s2.getc)\n    }\n  end\n\n  def test_getbyte\n    ssl_pair {|s1, s2|\n      s1 << \"a\"\n      assert_equal(97, s2.getbyte)\n    }\n  end\n\n  def test_readbyte\n    ssl_pair {|s1, s2|\n      s1 << \"b\"\n      assert_equal(98, s2.readbyte)\n    }\n  end\n\n  def test_readbyte_eof\n    ssl_pair {|s1, s2|\n      s2.close\n      assert_raise(EOFError) { s1.readbyte }\n    }\n  end\n\n  def test_gets\n    ssl_pair {|s1, s2|\n      s1 << \"abc\\n\\n$def123ghi\"\n      s1.close\n      ret = s2.gets\n      assert_equal Encoding::BINARY, ret.encoding\n      assert_equal \"abc\\n\", ret\n      assert_equal \"\\n$\", s2.gets(\"$\")\n      assert_equal \"def123\", s2.gets(/\\d+/)\n      assert_equal \"ghi\", s2.gets\n      assert_equal nil, s2.gets\n    }\n  end\n\n  def test_gets_chomp\n    ssl_pair {|s1, s2|\n      s1 << \"line1\\r\\nline2\\r\\nline3\\r\\n\"\n      s1.close\n\n      assert_equal(\"line1\", s2.gets(\"\\r\\n\", chomp: true))\n      assert_equal(\"line2\\r\\n\", s2.gets(\"\\r\\n\", chomp: false))\n      assert_equal(\"line3\", s2.gets(chomp: true))\n    }\n  end\n\n  def test_gets_eof_limit\n    ssl_pair {|s1, s2|\n      s1.write(\"hello\")\n      s1.close # trigger EOF\n      assert_match \"hello\", s2.gets(\"\\n\", 6), \"[ruby-core:70149] [Bug #11400]\"\n    }\n  end\n\n  def test_readpartial\n    ssl_pair {|s1, s2|\n      s2.write \"a\\nbcd\"\n      assert_equal(\"a\\n\", s1.gets)\n      result = String.new\n      result << s1.readpartial(10) until result.length == 3\n      assert_equal(\"bcd\", result)\n      s2.write \"efg\"\n      result = String.new\n      result << s1.readpartial(10) until result.length == 3\n      assert_equal(\"efg\", result)\n      s2.close\n      assert_raise(EOFError) { s1.readpartial(10) }\n      assert_raise(EOFError) { s1.readpartial(10) }\n      assert_equal(\"\", s1.readpartial(0))\n    }\n  end\n\n  def test_readall\n    ssl_pair {|s1, s2|\n      s2.close\n      assert_equal(\"\", s1.read)\n    }\n  end\n\n  def test_readline\n    ssl_pair {|s1, s2|\n      s2.close\n      assert_raise(EOFError) { s1.readline }\n    }\n  end\n\n  def test_puts_empty\n    ssl_pair {|s1, s2|\n      s1.puts\n      s1.close\n      assert_equal(\"\\n\", s2.read)\n    }\n  end\n\n  def test_multibyte_read_write\n    # German a umlaut\n    auml = [%w{ C3 A4 }.join('')].pack('H*')\n    auml.force_encoding(Encoding::UTF_8)\n    bsize = auml.bytesize\n\n    ssl_pair { |s1, s2|\n      assert_equal bsize, s1.write(auml)\n      read = s2.read(bsize)\n      assert_equal Encoding::ASCII_8BIT, read.encoding\n      assert_equal bsize, read.bytesize\n      assert_equal auml, read.force_encoding(Encoding::UTF_8)\n\n      s1.puts(auml)\n      read = s2.gets\n      assert_equal Encoding::ASCII_8BIT, read.encoding\n      assert_equal bsize + 1, read.bytesize\n      assert_equal auml + \"\\n\", read.force_encoding(Encoding::UTF_8)\n    }\n  end\n\n  def test_read_nonblock\n    ssl_pair {|s1, s2|\n      err = nil\n      assert_raise(OpenSSL::SSL::SSLErrorWaitReadable) {\n        begin\n          s2.read_nonblock(10)\n        ensure\n          err = $!\n        end\n      }\n      assert_kind_of(IO::WaitReadable, err)\n      s1.write \"abc\\ndef\\n\"\n      IO.select([s2])\n      assert_equal(\"ab\", s2.read_nonblock(2))\n      assert_equal(\"c\\n\", s2.gets)\n      ret = nil\n      assert_nothing_raised(\"[ruby-core:20298]\") { ret = s2.read_nonblock(10) }\n      assert_equal(\"def\\n\", ret)\n      s1.close\n      IO.select([s2])\n      assert_raise(EOFError) { s2.read_nonblock(10) }\n    }\n  end\n\n  def test_read_nonblock_no_exception\n    ssl_pair {|s1, s2|\n      assert_equal :wait_readable, s2.read_nonblock(10, exception: false)\n      s1.write \"abc\\ndef\\n\"\n      IO.select([s2])\n      assert_equal(\"ab\", s2.read_nonblock(2, exception: false))\n      assert_equal(\"c\\n\", s2.gets)\n      ret = nil\n      assert_nothing_raised(\"[ruby-core:20298]\") { ret = s2.read_nonblock(10, exception: false) }\n      assert_equal(\"def\\n\", ret)\n      s1.close\n      IO.select([s2])\n      assert_equal(nil, s2.read_nonblock(10, exception: false))\n    }\n  end\n\n  def test_read_with_outbuf\n    ssl_pair { |s1, s2|\n      s1.write(\"abc\\n\")\n      buf = String.new\n      ret = s2.read(2, buf)\n      assert_same ret, buf\n      assert_equal \"ab\", ret\n\n      buf = +\"garbage\"\n      ret = s2.read(2, buf)\n      assert_same ret, buf\n      assert_equal \"c\\n\", ret\n\n      buf = +\"garbage\"\n      assert_equal :wait_readable, s2.read_nonblock(100, buf, exception: false)\n      assert_equal \"garbage\", buf\n\n      s1.close\n      buf = +\"garbage\"\n      assert_nil s2.read(100, buf)\n      assert_equal \"\", buf\n\n      buf = +\"garbage\"\n      ret = s2.read(0, buf)\n      assert_same buf, ret\n      assert_equal \"\", ret\n    }\n  end\n\n  def test_write_nonblock\n    ssl_pair {|s1, s2|\n      assert_equal 3, s1.write_nonblock(\"foo\")\n      assert_equal \"foo\", s2.read(3)\n\n      data = \"x\" * 16384\n      written = 0\n      while true\n        begin\n          written += s1.write_nonblock(data)\n        rescue IO::WaitWritable, IO::WaitReadable\n          break\n        end\n      end\n      assert written > 0\n      assert_equal written, s2.read(written).bytesize\n    }\n  end\n\n  def test_write_nonblock_no_exceptions\n    ssl_pair {|s1, s2|\n      assert_equal 3, s1.write_nonblock(\"foo\", exception: false)\n      assert_equal \"foo\", s2.read(3)\n\n      data = \"x\" * 16384\n      written = 0\n      while true\n        case ret = s1.write_nonblock(data, exception: false)\n        when :wait_readable, :wait_writable\n          break\n        else\n          written += ret\n        end\n      end\n      assert written > 0\n      assert_equal written, s2.read(written).bytesize\n    }\n  end\n\n  def test_write_nonblock_with_buffered_data\n    ssl_pair {|s1, s2|\n      s1.write \"foo\"\n      s1.write_nonblock(\"bar\")\n      s1.write \"baz\"\n      s1.close\n      assert_equal(\"foobarbaz\", s2.read)\n    }\n  end\n\n  def test_write_nonblock_with_buffered_data_no_exceptions\n    ssl_pair {|s1, s2|\n      s1.write \"foo\"\n      s1.write_nonblock(\"bar\", exception: false)\n      s1.write \"baz\"\n      s1.close\n      assert_equal(\"foobarbaz\", s2.read)\n    }\n  end\n\n  def test_write_nonblock_retry\n    ssl_pair {|s1, s2|\n      # fill up a socket so we hit EAGAIN\n      written = String.new\n      n = 0\n      buf = 'a' * 4099\n      case ret = s1.write_nonblock(buf, exception: false)\n      when :wait_readable then break\n      when :wait_writable then break\n      when Integer\n        written << buf\n        n += ret\n        exp = buf.bytesize\n        if ret != exp\n          buf = buf.byteslice(ret, exp - ret)\n        end\n      end while true\n      assert_kind_of Symbol, ret\n\n      # make more space for subsequent write:\n      readed = s2.read(n)\n      assert_equal written, readed\n\n      # this fails if SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is missing:\n      buf2 = Marshal.load(Marshal.dump(buf))\n      assert_kind_of Integer, s1.write_nonblock(buf2, exception: false)\n    }\n  end\n\n  def test_write_zero\n    ssl_pair {|s1, s2|\n      assert_equal 0, s2.write_nonblock('', exception: false)\n      assert_kind_of Symbol, s1.read_nonblock(1, exception: false)\n      assert_equal 0, s2.syswrite('')\n      assert_kind_of Symbol, s1.read_nonblock(1, exception: false)\n      assert_equal 0, s2.write('')\n      assert_kind_of Symbol, s1.read_nonblock(1, exception: false)\n    }\n  end\n\n  def test_write_multiple_arguments\n    ssl_pair {|s1, s2|\n      str1 = \"foo\"; str2 = \"bar\"\n      assert_equal 6, s1.write(str1, str2)\n      s1.close\n      assert_equal \"foobar\", s2.read\n    }\n  end\n\n  def test_partial_tls_record_read_nonblock\n    ssl_pair { |s1, s2|\n      # the beginning of a TLS record\n      s1.io.write(\"\\x17\")\n      # should raise a IO::WaitReadable since a full TLS record is not available\n      # for reading\n      assert_raise(IO::WaitReadable) { s2.read_nonblock(1) }\n    }\n  end\n\n  def tcp_pair\n    host = \"127.0.0.1\"\n    serv = TCPServer.new(host, 0)\n    port = serv.connect_address.ip_port\n    sock1 = TCPSocket.new(host, port)\n    sock2 = serv.accept\n    serv.close\n    [sock1, sock2]\n  ensure\n    serv.close if serv && !serv.closed?\n  end\n\n  def test_connect_accept_nonblock_no_exception\n    ctx2 = OpenSSL::SSL::SSLContext.new\n    ctx2.cert = @svr_cert\n    ctx2.key = @svr_key\n\n    sock1, sock2 = tcp_pair\n\n    s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)\n    accepted = s2.accept_nonblock(exception: false)\n    assert_equal :wait_readable, accepted\n\n    ctx1 = OpenSSL::SSL::SSLContext.new\n    s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)\n    th = Thread.new do\n      rets = []\n      begin\n        rv = s1.connect_nonblock(exception: false)\n        rets << rv\n        case rv\n        when :wait_writable\n          IO.select(nil, [s1], nil, 5)\n        when :wait_readable\n          IO.select([s1], nil, nil, 5)\n        end\n      end until rv == s1\n      rets\n    end\n\n    until th.join(0.01)\n      accepted = s2.accept_nonblock(exception: false)\n      assert_include([s2, :wait_readable, :wait_writable ], accepted)\n    end\n\n    rets = th.value\n    assert_instance_of Array, rets\n    rets.each do |rv|\n      assert_include([s1, :wait_readable, :wait_writable ], rv)\n    end\n  ensure\n    th.join if th\n    s1.close if s1\n    s2.close if s2\n    sock1.close if sock1\n    sock2.close if sock2\n    accepted.close if accepted.respond_to?(:close)\n  end\n\n  def test_connect_accept_nonblock\n    ctx = OpenSSL::SSL::SSLContext.new\n    ctx.cert = @svr_cert\n    ctx.key = @svr_key\n\n    sock1, sock2 = tcp_pair\n\n    th = Thread.new {\n      s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx)\n      5.times {\n        begin\n          break s2.accept_nonblock\n        rescue IO::WaitReadable\n          IO.select([s2], nil, nil, 1)\n        rescue IO::WaitWritable\n          IO.select(nil, [s2], nil, 1)\n        end\n        sleep 0.2\n      }\n    }\n\n    s1 = OpenSSL::SSL::SSLSocket.new(sock1)\n    5.times {\n      begin\n        break s1.connect_nonblock\n      rescue IO::WaitReadable\n        IO.select([s1], nil, nil, 1)\n      rescue IO::WaitWritable\n        IO.select(nil, [s1], nil, 1)\n      end\n      sleep 0.2\n    }\n\n    s2 = th.value\n\n    s1.print \"a\\ndef\"\n    assert_equal(\"a\\n\", s2.gets)\n  ensure\n    sock1&.close\n    sock2&.close\n    th&.join\n  end\nend\n\nclass OpenSSL::TestEOF1 < OpenSSL::TestCase\n  include OpenSSL::TestEOF\n  include OpenSSL::SSLPair\n  include OpenSSL::TestEOF1M\nend\n\nclass OpenSSL::TestEOF1LowlevelSocket < OpenSSL::TestCase\n  include OpenSSL::TestEOF\n  include OpenSSL::SSLPairLowlevelSocket\n  include OpenSSL::TestEOF1M\nend\n\nclass OpenSSL::TestEOF2 < OpenSSL::TestCase\n  include OpenSSL::TestEOF\n  include OpenSSL::SSLPair\n  include OpenSSL::TestEOF2M\nend\n\nclass OpenSSL::TestEOF2LowlevelSocket < OpenSSL::TestCase\n  include OpenSSL::TestEOF\n  include OpenSSL::SSLPairLowlevelSocket\n  include OpenSSL::TestEOF2M\nend\n\nclass OpenSSL::TestPair < OpenSSL::TestCase\n  include OpenSSL::SSLPair\n  include OpenSSL::TestPairM\nend\n\nclass OpenSSL::TestPairLowlevelSocket < OpenSSL::TestCase\n  include OpenSSL::SSLPairLowlevelSocket\n  include OpenSSL::TestPairM\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_pkcs12.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\n# OpenSSL::PKCS12.create calling the PKCS12_create() has the argument mac_iter\n# which uses a MAC key using PKCS12KDF which is not FIPS-approved.\n# OpenSSL::PKCS12.new with base64-encoded example calling PKCS12_parse()\n# verifies the MAC key using PKCS12KDF which is not FIPS-approved.\n#\n# PBE-SHA1-3DES uses PKCS12KDF which is not FIPS-approved according to the RFC\n# 7292 PKCS#12.\n# https://datatracker.ietf.org/doc/html/rfc7292#appendix-C\n# > The PBES1 encryption scheme defined in PKCS #5 provides a number of\n# > algorithm identifiers for deriving keys and IVs; here, we specify a\n# > few more, all of which use the procedure detailed in Appendices B.2\n# > and B.3 to construct keys (and IVs, where needed).  As is implied by\n# > their names, all of the object identifiers below use the hash\n# > function SHA-1.\n# > ...\n# > pbeWithSHAAnd3-KeyTripleDES-CBC  OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3}\n#\n# Note that the pbeWithSHAAnd3-KeyTripleDES-CBC (pkcs12-pbeids 3) in the RFC\n# 7292 PKCS#12 means PBE-SHA1-3DES in OpenSSL. PKCS12KDF is used in PKCS#12.\n# https://oidref.com/1.2.840.113549.1.12.1.3\n# https://github.com/openssl/openssl/blob/ed57d1e06dca28689190e00d9893e0fd7ecc67c1/crypto/objects/objects.txt#L385\nreturn if OpenSSL.fips_mode\n\nmodule OpenSSL\n  class TestPKCS12 < OpenSSL::TestCase\n    DEFAULT_PBE_PKEYS = \"PBE-SHA1-3DES\"\n    DEFAULT_PBE_CERTS = \"PBE-SHA1-3DES\"\n\n    def setup\n      super\n      ca = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=CA\")\n      ca_exts = [\n        [\"basicConstraints\",\"CA:TRUE\",true],\n        [\"keyUsage\",\"keyCertSign, cRLSign\",true],\n        [\"subjectKeyIdentifier\",\"hash\",false],\n        [\"authorityKeyIdentifier\",\"keyid:always\",false],\n      ]\n      ca_key = Fixtures.pkey(\"rsa-1\")\n      @cacert = issue_cert(ca, ca_key, 1, ca_exts, nil, nil)\n\n      inter_ca = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=Intermediate CA\")\n      inter_ca_key = Fixtures.pkey(\"rsa-2\")\n      @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, ca_key)\n\n      exts = [\n        [\"keyUsage\",\"digitalSignature\",true],\n        [\"subjectKeyIdentifier\",\"hash\",false],\n      ]\n      ee = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate\")\n      @mykey = Fixtures.pkey(\"rsa-3\")\n      @mycert = issue_cert(ee, @mykey, 3, exts, @inter_cacert, inter_ca_key)\n    end\n\n    def test_create_single_key_single_cert\n      pkcs12 = OpenSSL::PKCS12.create(\n        \"omg\",\n        \"hello\",\n        @mykey,\n        @mycert,\n        nil,\n        DEFAULT_PBE_PKEYS,\n        DEFAULT_PBE_CERTS,\n      )\n      assert_equal @mycert, pkcs12.certificate\n      assert_equal @mykey.to_der, pkcs12.key.to_der\n      assert_nil pkcs12.ca_certs\n\n      der = pkcs12.to_der\n      decoded = OpenSSL::PKCS12.new(der, \"omg\")\n      assert_equal @mykey.to_der, decoded.key.to_der\n      assert_equal @mycert, decoded.certificate\n      assert_equal [], Array(decoded.ca_certs)\n    end\n\n    def test_create_no_pass\n      pkcs12 = OpenSSL::PKCS12.create(\n        nil,\n        \"hello\",\n        @mykey,\n        @mycert,\n        nil,\n        DEFAULT_PBE_PKEYS,\n        DEFAULT_PBE_CERTS,\n      )\n      assert_equal @mycert, pkcs12.certificate\n      assert_equal @mykey.to_der, pkcs12.key.to_der\n      assert_nil pkcs12.ca_certs\n\n      decoded = OpenSSL::PKCS12.new(pkcs12.to_der)\n      assert_equal @mycert, decoded.certificate\n    end\n\n    def test_create_with_chain\n      chain = [@inter_cacert, @cacert]\n\n      pkcs12 = OpenSSL::PKCS12.create(\n        \"omg\",\n        \"hello\",\n        @mykey,\n        @mycert,\n        chain,\n        DEFAULT_PBE_PKEYS,\n        DEFAULT_PBE_CERTS,\n      )\n      assert_equal chain, pkcs12.ca_certs\n    end\n\n    def test_create_with_chain_decode\n      chain = [@cacert, @inter_cacert]\n\n      passwd = \"omg\"\n\n      pkcs12 = OpenSSL::PKCS12.create(\n        passwd,\n        \"hello\",\n        @mykey,\n        @mycert,\n        chain,\n        DEFAULT_PBE_PKEYS,\n        DEFAULT_PBE_CERTS,\n      )\n\n      decoded = OpenSSL::PKCS12.new(pkcs12.to_der, passwd)\n      assert_equal chain.size, decoded.ca_certs.size\n      assert_include decoded.ca_certs, @cacert\n      assert_include decoded.ca_certs, @inter_cacert\n      assert_equal @mycert, decoded.certificate\n      assert_equal @mykey.to_der, decoded.key.to_der\n    end\n\n    def test_create_with_bad_nid\n      assert_raise(ArgumentError) do\n        OpenSSL::PKCS12.create(\n          \"omg\",\n          \"hello\",\n          @mykey,\n          @mycert,\n          [],\n          \"foo\"\n        )\n      end\n    end\n\n    def test_create_with_itr\n      OpenSSL::PKCS12.create(\n        \"omg\",\n        \"hello\",\n        @mykey,\n        @mycert,\n        [],\n        DEFAULT_PBE_PKEYS,\n        DEFAULT_PBE_CERTS,\n        2048\n      )\n\n      assert_raise(TypeError) do\n        OpenSSL::PKCS12.create(\n          \"omg\",\n          \"hello\",\n          @mykey,\n          @mycert,\n          [],\n          DEFAULT_PBE_PKEYS,\n          DEFAULT_PBE_CERTS,\n          \"omg\"\n        )\n      end\n    end\n\n    def test_create_with_mac_itr\n      OpenSSL::PKCS12.create(\n        \"omg\",\n        \"hello\",\n        @mykey,\n        @mycert,\n        [],\n        DEFAULT_PBE_PKEYS,\n        DEFAULT_PBE_CERTS,\n        nil,\n        2048\n      )\n\n      assert_raise(TypeError) do\n        OpenSSL::PKCS12.create(\n          \"omg\",\n          \"hello\",\n          @mykey,\n          @mycert,\n          [],\n          DEFAULT_PBE_PKEYS,\n          DEFAULT_PBE_CERTS,\n          nil,\n          \"omg\"\n        )\n      end\n    end\n\n    def test_create_with_keytype\n      omit \"AWS-LC does not support KEY_SIG and KEY_EX\" if aws_lc?\n\n      OpenSSL::PKCS12.create(\n        \"omg\",\n        \"hello\",\n        @mykey,\n        @mycert,\n        [],\n        DEFAULT_PBE_PKEYS,\n        DEFAULT_PBE_CERTS,\n        nil,\n        nil,\n        OpenSSL::PKCS12::KEY_SIG\n      )\n\n      assert_raise(ArgumentError) do\n        OpenSSL::PKCS12.create(\n          \"omg\",\n          \"hello\",\n          @mykey,\n          @mycert,\n          [],\n          DEFAULT_PBE_PKEYS,\n          DEFAULT_PBE_CERTS,\n          nil,\n          nil,\n          2048\n        )\n      end\n    end\n\n    def test_new_with_no_keys\n      # Generated with the following steps:\n      #   Print the value of the @mycert such as by `puts @mycert.to_s` and\n      #   save the value as the file `mycert.pem`.\n      #   Run the following commands:\n      #   openssl pkcs12 -certpbe PBE-SHA1-3DES -in <(cat mycert.pem) \\\n      #     -nokeys -export -passout pass:abc123 -out /tmp/p12.out\n      #   base64 -w 60 /tmp/p12.out\n      str = <<~EOF.unpack1(\"m\")\nMIIGJAIBAzCCBeoGCSqGSIb3DQEHAaCCBdsEggXXMIIF0zCCBc8GCSqGSIb3\nDQEHBqCCBcAwggW8AgEAMIIFtQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQMw\nDgQIjv5c3OHvnBgCAggAgIIFiMJa8Z/w7errRvCQPXh9dGQz3eJaFq3S2gXD\nrh6oiwsgIRJZvYAWgU6ll9NV7N5SgvS2DDNVuc3tsP8TPWjp+bIxzS9qmGUV\nkYWuURWLMKhpF12ZRDab8jcIwBgKoSGiDJk8xHjx6L613/XcRM6ln3VeQK+C\nhlW5kXniNAUAgTft25Fn61Xa8xnhmsz/fk1ycGnyGjKCnr7Mgy7KV0C1vs23\n18n8+b1ktDWLZPYgpmXuMFVh0o+HJTV3O86mkIhJonMcnOMgKZ+i8KeXaocN\nJQlAPBG4+HOip7FbQT/h6reXv8/J+hgjLfqAb5aV3m03rUX9mXx66nR1tQU0\nJq+XPfDh5+V4akIczLlMyyo/xZjI1/qupcMjr+giOGnGd8BA3cuXW+ueLQiA\nPpTp+DQLVHRfz9XTZbyqOReNEtEXvO9gOlKSEY5lp65ItXVEs2Oqyf9PfU9y\nDUltN6fCMilwPyyrsIBKXCu2ZLM5h65KVCXAYEX9lNqj9zrQ7vTqvCNN8RhS\nScYouTX2Eqa4Z+gTZWLHa8RCQFoyP6hd+97/Tg2Gv2UTH0myQxIVcnpdi1wy\ncqb+er7tyKbcO96uSlUjpj/JvjlodtjJcX+oinEqGb/caj4UepbBwiG3vv70\n63bS3jTsOLNjDRsR9if3LxIhLa6DW8zOJiGC+EvMD1o4dzHcGVpQ/pZWCHZC\n+YiNJpQOBApiZluE+UZ0m3XrtHFQYk7xblTrh+FJF91wBsok0rZXLAKd8m4p\nOJsc7quCq3cuHRRTzJQ4nSe01uqbwGDAYwLvi6VWy3svU5qa05eDRmgzEFTG\ne84Gp/1LQCtpQFr4txkjFchO2whWS80KoQKqmLPyGm1D9Lv53Q4ZsKMgNihs\nrEepuaOZMKHl4yMAYFoOXZCAYzfbhN6b2phcFAHjMUHUw9e3F0QuDk9D0tsr\nriYTrkocqlOKfK4QTomx27O0ON2J6f1rtEojGgfl9RNykN7iKGzjS3914QjW\nW6gGiZejxHsDPEAa4gUp0WiSUSXtD5WJgoyAzLydR2dKWsQ4WlaUXi01CuGy\n+xvncSn2nO3bbot8VD5H6XU1CjREVtnIfbeRYO/uofyLUP3olK5RqN6ne6Xo\neXnJ/bjYphA8NGuuuvuW1SCITmINkZDLC9cGlER9+K65RR/DR3TigkexXMeN\naJ70ivZYAl0OuhZt3TGIlAzS64TIoyORe3z7Ta1Pp9PZQarYJpF9BBIZIFor\n757PHHuQKRuugiRkp8B7v4eq1BQ+VeAxCKpyZ7XrgEtbY/AWDiaKcGPKPjc3\nAqQraVeQm7kMBT163wFmZArCphzkDOI3bz2oEO8YArMgLq2Vto9jAZlqKyWr\npi2bSJxuoP1aoD58CHcWMrf8/j1LVdQhKgHQXSik2ID0H2Wc/XnglhzlVFuJ\nJsNIW/EGJlZh/5WDez9U0bXqnBlu3uasPEOezdoKlcCmQlmTO5+uLHYLEtNA\nEH9MtnGZebi9XS5meTuS6z5LILt8O9IHZxmT3JRPHYj287FEzotlLdcJ4Ee5\nenW41UHjLrfv4OaITO1hVuoLRGdzjESx/fHMWmxroZ1nVClxECOdT42zvIYJ\nJ3xBZ0gppzQ5fjoYiKjJpxTflRxUuxshk3ih6VUoKtqj/W18tBQ3g5SOlkgT\nyCW8r74yZlfYmNrPyDMUQYpLUPWj2n71GF0KyPfTU5yOatRgvheh262w5BG3\nomFY7mb3tCv8/U2jdMIoukRKacpZiagofz3SxojOJq52cHnCri+gTHBMX0cO\nj58ygfntHWRzst0pV7Ze2X3fdCAJ4DokH6bNJNthcgmolFJ/y3V1tJjgsdtQ\n7Pjn/vE6xUV0HXE2x4yoVYNirbAMIvkN/X+atxrN0dA4AchN+zGp8TAxMCEw\nCQYFKw4DAhoFAAQUQ+6XXkyhf6uYgtbibILN2IjKnOAECLiqoY45MPCrAgII\nAA==\n      EOF\n      p12 = OpenSSL::PKCS12.new(str, \"abc123\")\n\n      assert_equal nil, p12.key\n      assert_equal nil, p12.certificate\n      assert_equal 1, p12.ca_certs.size\n      assert_equal @mycert.subject, p12.ca_certs[0].subject\n    end\n\n    def test_new_with_no_certs\n      # Generated with the folowing steps:\n      #   openssl pkcs12 -inkey test/openssl/fixtures/pkey/rsa-1.pem \\\n      #     -nocerts -export -passout pass:abc123 -out /tmp/p12.out\n      #   base64 -w 60 /tmp/p12.out\n      str = <<~EOF.unpack1(\"m\")\nMIIJ7wIBAzCCCbUGCSqGSIb3DQEHAaCCCaYEggmiMIIJnjCCCZoGCSqGSIb3\nDQEHAaCCCYsEggmHMIIJgzCCCX8GCyqGSIb3DQEMCgECoIIJbjCCCWowHAYK\nKoZIhvcNAQwBAzAOBAjX5nN8jyRKwQICCAAEgglIBIRLHfiY1mNHpl3FdX6+\n72L+ZOVXnlZ1MY9HSeg0RMkCJcm0mJ2UD7INUOGXvwpK9fr6WJUZM1IqTihQ\n1dM0crRC2m23aP7KtAlXh2DYD3otseDtwoN/NE19RsiJzeIiy5TSW1d47weU\n+D4Ig/9FYVFPTDgMzdCxXujhvO/MTbZIjqtcS+IOyF+91KkXrHkfkGjZC7KS\nWRmYw9BBuIPQEewdTI35sAJcxT8rK7JIiL/9mewbSE+Z28Wq1WXwmjL3oZm9\nlw6+f515b197GYEGomr6LQqJJamSYpwQbTGHonku6Tf3ylB4NLFqOnRCKE4K\nzRSSYIqJBlKHmQ4pDm5awoupHYxMZLZKZvXNYyYN3kV8r1iiNVlY7KBR4CsX\nrqUkXehRmcPnuqEMW8aOpuYe/HWf8PYI93oiDZjcEZMwW2IZFFrgBbqUeNCM\nCQTkjAYxi5FyoaoTnHrj/aRtdLOg1xIJe4KKcmOXAVMmVM9QEPNfUwiXJrE7\nn42gl4NyzcZpxqwWBT++9TnQGZ/lEpwR6dzkZwICNQLdQ+elsdT7mumywP+1\nWaFqg9kpurimaiBu515vJNp9Iqv1Nmke6R8Lk6WVRKPg4Akw0fkuy6HS+LyN\nofdCfVUkPGN6zkjAxGZP9ZBwvXUbLRC5W3N5qZuAy5WcsS75z+oVeX9ePV63\ncue23sClu8JSJcw3HFgPaAE4sfkQ4MoihPY5kezgT7F7Lw/j86S0ebrDNp4N\nY685ec81NRHJ80CAM55f3kGCOEhoifD4VZrvr1TdHZY9Gm3b1RYaJCit2huF\nnlOfzeimdcv/tkjb6UsbpXx3JKkF2NFFip0yEBERRCdWRYMUpBRcl3ad6XHy\nw0pVTgIjTxGlbbtOCi3siqMOK0GNt6UgjoEFc1xqjsgLwU0Ta2quRu7RFPGM\nGoEwoC6VH23p9Hr4uTFOL0uHfkKWKunNN+7YPi6LT6IKmTQwrp+fTO61N6Xh\nKlqTpwESKsIJB2iMnc8wBkjXJtmG/e2n5oTqfhICIrxYmEb7zKDyK3eqeTj3\nFhQh2t7cUIiqcT52AckUqniPmlE6hf82yBjhaQUPfi/ExTBtTDSmFfRPUzq+\nRlla4OHllPRzUXJExyansgCxZbPqlw46AtygSWRGcWoYAKUKwwoYjerqIV5g\nJoZICV9BOU9TXco1dHXZQTs/nnTwoRmYiL/Ly5XpvUAnQOhYeCPjBeFnPSBR\nR/hRNqrDH2MOV57v5KQIH2+mvy26tRG+tVGHmLMaOJeQkjLdxx+az8RfXIrH\n7hpAsoBb+g9jUDY1mUVavPk1T45GMpQH8u3kkzRvChfOst6533GyIZhE7FhN\nKanC6ACabVFDUs6P9pK9RPQMp1qJfpA0XJFx5TCbVbPkvnkZd8K5Tl/tzNM1\nn32eRao4MKr9KDwoDL93S1yJgYTlYjy1XW/ewdedtX+B4koAoz/wSXDYO+GQ\nZu6ZSpKSEHTRPhchsJ4oICvpriVaJkn0/Z7H3YjNMB9U5RR9+GiIg1wY1Oa1\nS3WfuwrrI6eqfbQwj6PDNu3IKy6srEgvJwaofQALNBPSYWbauM2brc8qsD+t\nn8jC/aD1aMcy00+9t3H/RVCjEOb3yKfUpAldIkEA2NTTnZpoDQDXeNYU2F/W\nyhmFjJy8A0O4QOk2xnZK9kcxSRs0v8vI8HivvgWENoVPscsDC4742SSIe6SL\nf/T08reIX11f0K70rMtLhtFMQdHdYOTNl6JzhkHPLr/f9MEZsBEQx52depnF\nARb3gXGbCt7BAi0OeCEBSbLr2yWuW4r55N0wRZSOBtgqgjsiHP7CDQSkbL6p\nFPlQS1do9gBSHiNYvsmN1LN5bG+mhcVb0UjZub4mL0EqGadjDfDdRJmWqlX0\nr5dyMcOWQVy4O2cPqYFlcP9lk8buc5otcyVI2isrAFdlvBK29oK6jc52Aq5Q\n0b2ESDlgX8WRgiOPPxK8dySKEeuIwngCtJyNTecP9Ug06TDsu0znZGCXJ+3P\n8JOpykgA8EQdOZOYHbo76ZfB2SkklI5KeRA5IBjGs9G3TZ4PHLy2DIwsbWzS\nH1g01o1x264nx1cJ+eEgUN/KIiGFIib42RS8Af4D5e+Vj54Rt3axq+ag3kI+\n53p8uotyu+SpvvXUP7Kv4xpQ/L6k41VM0rfrd9+DrlDVvSfxP2uh6I1TKF7A\nCT5n8zguMbng4PGjxvyPBM5k62t6hN5fuw6Af0aZFexh+IjB/5wFQ6onSz23\nfBzMW4St7RgSs8fDg3lrM+5rwXiey1jxY1ddaxOoUsWRMvvdd7rZxRZQoN5v\nAcI5iMkK/vvpQgC/sfzhtXtrJ2XOPZ+GVgi7VcuDLKSkdFMcPbGzO8SdxUnS\nSLV5XTKqKND+Lrfx7DAoKi5wbDFHu5496/MHK5qP4tBe6sJ5bZc+KDJIH46e\nwTV1oWtB5tV4q46hOb5WRcn/Wjz3HSKaGZgx5QbK1MfKTzD5CTUn+ArMockX\n2wJhPnFK85U4rgv8iBuh9bRjyw+YaKf7Z3loXRiE1eRG6RzuPF0ZecFiDumk\nAC/VUXynJhzePBLqzrQj0exanACdullN+pSfHiRWBxR2VFUkjoFP5X45GK3z\nOstSH6FOkMVU4afqEmjsIwozDFIyin5EyWTtdhJe3szdJSGY23Tut+9hUatx\n9FDFLESOd8z3tyQSNiLk/Hib+e/lbjxqbXBG/p/oyvP3N999PLUPtpKqtYkV\nH0+18sNh9CVfojiJl44fzxe8yCnuefBjut2PxEN0EFRBPv9P2wWlmOxkPKUq\nNrCJP0rDj5aONLrNZPrR8bZNdIShkZ/rKkoTuA0WMZ+xUlDRxAupdMkWAlrz\n8IcwNcdDjPnkGObpN5Ctm3vK7UGSBmPeNqkXOYf3QTJ9gStJEd0F6+DzTN5C\nKGt1IyuGwZqL2Yk51FDIIkr9ykEnBMaA39LS7GFHEDNGlW+fKC7AzA0zfoOr\nfXZlHMBuqHtXqk3zrsHRqGGoocigg4ctrhD1UREYKj+eIj1TBiRdf7c6+COf\nNIOmej8pX3FmZ4ui+dDA8r2ctgsWHrb4A6iiH+v1DRA61GtoaA/tNRggewXW\nVXCZCGWyyTuyHGOqq5ozrv5MlzZLWD/KV/uDsAWmy20RAed1C4AzcXlpX25O\nM4SNl47g5VRNJRtMqokc8j6TjZrzMDEwITAJBgUrDgMCGgUABBRrkIRuS5qg\nBC8fv38mue8LZVcbHQQIUNrWKEnskCoCAggA\n      EOF\n      p12 = OpenSSL::PKCS12.new(str, \"abc123\")\n\n      assert_equal Fixtures.pkey(\"rsa-1\").to_der, p12.key.to_der\n      assert_equal nil, p12.certificate\n      assert_equal [], Array(p12.ca_certs)\n    end\n\n    def test_dup\n      p12 = OpenSSL::PKCS12.create(\n        \"pass\",\n        \"name\",\n        @mykey,\n        @mycert,\n        nil,\n        DEFAULT_PBE_PKEYS,\n        DEFAULT_PBE_CERTS,\n      )\n      assert_equal p12.to_der, p12.dup.to_der\n    end\n\n    def test_set_mac_pkcs12kdf\n      p12 = OpenSSL::PKCS12.create(\n        \"pass\",\n        \"name\",\n        @mykey,\n        @mycert,\n        nil,\n        nil,\n        nil,\n        nil,\n        1234, # mac_iter\n        nil,\n      )\n      macdata = macdata(p12)\n      # Depends on the OpenSSL version: SHA256 in OpenSSL >= 3.0\n      assert_include [\"SHA1\", \"SHA256\"], macdata[:mac_algo]\n      assert_equal 1234, macdata[:iter]\n\n      p12.set_mac(\"pass\", \"macsalt\", 2345, \"SHA384\")\n      macdata = macdata(p12)\n      assert_equal \"SHA384\", macdata[:mac_algo]\n      assert_equal \"macsalt\", macdata[:salt]\n      assert_equal 2345, macdata[:iter]\n      assert_equal @mykey.to_der, OpenSSL::PKCS12.new(p12.to_der, \"pass\").key.to_der\n    end\n\n    private\n\n    def macdata(p12)\n      # See RFC 7292\n      asn1 = OpenSSL::ASN1.decode(p12.to_der)\n      macdata = asn1.value[2]\n      mac = macdata.value[0]\n      mac_algo = mac.value[0].value[0].value\n      _mac_params = mac.value[0].value[1]\n      {\n        mac_algo: mac_algo,\n        salt: macdata.value[1].value,\n        iter: macdata.value[2]&.value,\n      }\n    end\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_pkcs7.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestPKCS7 < OpenSSL::TestCase\n  def setup\n    super\n    @ca_key = Fixtures.pkey(\"rsa-1\")\n    @ee1_key = Fixtures.pkey(\"rsa-2\")\n    @ee2_key = Fixtures.pkey(\"rsa-3\")\n    ca = OpenSSL::X509::Name.new([[\"CN\", \"CA\"]])\n    ee1 = OpenSSL::X509::Name.new([[\"CN\", \"EE1\"]])\n    ee2 = OpenSSL::X509::Name.new([[\"CN\", \"EE2\"]])\n\n    ca_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"keyCertSign, cRLSign\", true],\n      [\"subjectKeyIdentifier\", \"hash\", false],\n      [\"authorityKeyIdentifier\", \"keyid:always\", false],\n    ]\n    @ca_cert = issue_cert(ca, @ca_key, 1, ca_exts, nil, nil)\n    ee_exts = [\n      [\"keyUsage\", \"nonRepudiation, digitalSignature, keyEncipherment\", true],\n      [\"authorityKeyIdentifier\", \"keyid:always\", false],\n      [\"extendedKeyUsage\", \"clientAuth, emailProtection, codeSigning\", false],\n    ]\n    @ee1_cert = issue_cert(ee1, @ee1_key, 2, ee_exts, @ca_cert, @ca_key)\n    @ee2_cert = issue_cert(ee2, @ee2_key, 3, ee_exts, @ca_cert, @ca_key)\n  end\n\n  def test_signed\n    store = OpenSSL::X509::Store.new\n    store.add_cert(@ca_cert)\n\n    data = \"aaaaa\\nbbbbb\\nccccc\\n\"\n    ca_certs = [@ca_cert]\n    tmp = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data, ca_certs)\n    # TODO: #data contains untranslated content\n    assert_equal(\"aaaaa\\nbbbbb\\nccccc\\n\", tmp.data)\n    assert_nil(tmp.error_string)\n\n    p7 = OpenSSL::PKCS7.new(tmp.to_der)\n    assert_nil(p7.data)\n    assert_nil(p7.error_string)\n\n    assert_true(p7.verify([], store))\n    # AWS-LC does not appear to convert to CRLF automatically\n    assert_equal(\"aaaaa\\r\\nbbbbb\\r\\nccccc\\r\\n\", p7.data) unless aws_lc?\n    assert_nil(p7.error_string)\n\n    certs = p7.certificates\n    assert_equal(2, certs.size)\n    assert_equal(@ee1_cert.subject, certs[0].subject)\n    assert_equal(@ca_cert.subject, certs[1].subject)\n\n    signers = p7.signers\n    assert_equal(1, signers.size)\n    assert_equal(@ee1_cert.serial, signers[0].serial)\n    assert_equal(@ee1_cert.issuer, signers[0].issuer)\n    # AWS-LC does not generate authenticatedAttributes\n    assert_in_delta(Time.now, signers[0].signed_time, 10) unless aws_lc?\n\n    assert_false(p7.verify([@ca_cert], OpenSSL::X509::Store.new))\n  end\n\n  def test_signed_flags\n    store = OpenSSL::X509::Store.new\n    store.add_cert(@ca_cert)\n\n    # Normally OpenSSL tries to translate the supplied content into canonical\n    # MIME format (e.g. a newline character is converted into CR+LF).\n    # If the content is a binary, PKCS7::BINARY flag should be used.\n    #\n    # PKCS7::NOATTR flag suppresses authenticatedAttributes.\n    data = \"aaaaa\\nbbbbb\\nccccc\\n\"\n    flag = OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::NOATTR\n    tmp = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data, [@ca_cert], flag)\n    p7 = OpenSSL::PKCS7.new(tmp.to_der)\n\n    assert_true(p7.verify([], store))\n    assert_equal(data, p7.data)\n\n    certs = p7.certificates\n    assert_equal(2, certs.size)\n    assert_equal(@ee1_cert.subject, certs[0].subject)\n    assert_equal(@ca_cert.subject, certs[1].subject)\n\n    signers = p7.signers\n    assert_equal(1, signers.size)\n    assert_equal(@ee1_cert.serial, signers[0].serial)\n    assert_equal(@ee1_cert.issuer, signers[0].issuer)\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) { signers[0].signed_time }\n  end\n\n  def test_signed_multiple_signers\n    store = OpenSSL::X509::Store.new\n    store.add_cert(@ca_cert)\n\n    # A signed-data which have multiple signatures can be created\n    # through the following steps.\n    #   1. create two signed-data\n    #   2. copy signerInfo and certificate from one to another\n    data = \"aaaaa\\r\\nbbbbb\\r\\nccccc\\r\\n\"\n    tmp1 = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data)\n    tmp2 = OpenSSL::PKCS7.sign(@ee2_cert, @ee2_key, data)\n    tmp1.add_signer(tmp2.signers[0])\n    tmp1.add_certificate(@ee2_cert)\n\n    p7 = OpenSSL::PKCS7.new(tmp1.to_der)\n    assert_true(p7.verify([], store))\n    assert_equal(data, p7.data)\n\n    certs = p7.certificates\n    assert_equal(2, certs.size)\n\n    signers = p7.signers\n    assert_equal(2, signers.size)\n    assert_equal(@ee1_cert.serial, signers[0].serial)\n    assert_equal(@ee1_cert.issuer, signers[0].issuer)\n    assert_equal(@ee2_cert.serial, signers[1].serial)\n    assert_equal(@ee2_cert.issuer, signers[1].issuer)\n  end\n\n  def test_signed_add_signer\n    data = \"aaaaa\\nbbbbb\\nccccc\\n\"\n    psi = OpenSSL::PKCS7::SignerInfo.new(@ee1_cert, @ee1_key, \"sha256\")\n    p7 = OpenSSL::PKCS7.new\n    p7.type = :signed\n    p7.add_signer(psi)\n    p7.add_certificate(@ee1_cert)\n    p7.add_certificate(@ca_cert)\n    p7.add_data(data)\n\n    store = OpenSSL::X509::Store.new\n    store.add_cert(@ca_cert)\n\n    assert_equal(true, p7.verify([], store))\n    assert_equal(true, OpenSSL::PKCS7.new(p7.to_der).verify([], store))\n    assert_equal(1, p7.signers.size)\n  end\n\n  def test_detached_sign\n    store = OpenSSL::X509::Store.new\n    store.add_cert(@ca_cert)\n\n    data = \"aaaaa\\nbbbbb\\nccccc\\n\"\n    ca_certs = [@ca_cert]\n    flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED\n    tmp = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data, ca_certs, flag)\n    p7 = OpenSSL::PKCS7.new(tmp.to_der)\n    assert_predicate(p7, :detached?)\n    assert_true(p7.detached)\n\n    assert_false(p7.verify([], store))\n    # FIXME: Should it be nil?\n    assert_equal(\"\", p7.data)\n    assert_match(/no content|NO_CONTENT/, p7.error_string)\n\n    assert_true(p7.verify([], store, data))\n    assert_equal(data, p7.data)\n    assert_nil(p7.error_string)\n\n    certs = p7.certificates\n    assert_equal(2, certs.size)\n    assert_equal(@ee1_cert.subject, certs[0].subject)\n    assert_equal(@ca_cert.subject, certs[1].subject)\n\n    signers = p7.signers\n    assert_equal(1, signers.size)\n    assert_equal(@ee1_cert.serial, signers[0].serial)\n    assert_equal(@ee1_cert.issuer, signers[0].issuer)\n  end\n\n  def test_signed_authenticated_attributes\n    # Using static PEM data because AWS-LC does not support generating one\n    # with authenticatedAttributes.\n    #\n    # p7 was generated with OpenSSL 3.4.1 with this program with commandline\n    # \"faketime 2025-04-03Z ruby prog.rb\":\n    #\n    #   require_relative \"test/openssl/utils\"\n    #   include OpenSSL::TestUtils\n    #   key = Fixtures.pkey(\"p256\")\n    #   cert = issue_cert(OpenSSL::X509::Name.new([[\"CN\", \"cert\"]]), key, 1, [], nil, nil)\n    #   p7 = OpenSSL::PKCS7.sign(cert, key, \"content\", [])\n    #   puts p7.to_pem\n    p7 = OpenSSL::PKCS7.new(<<~EOF)\n-----BEGIN PKCS7-----\nMIICvgYJKoZIhvcNAQcCoIICrzCCAqsCAQExDzANBglghkgBZQMEAgEFADAWBgkq\nhkiG9w0BBwGgCQQHY29udGVudKCCAQ4wggEKMIGxoAMCAQICAQEwCgYIKoZIzj0E\nAwIwDzENMAsGA1UEAwwEY2VydDAeFw0yNTA0MDIyMzAwMDFaFw0yNTA0MDMwMTAw\nMDFaMA8xDTALBgNVBAMMBGNlcnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQW\nCWTZz6hVQgpDrh5kb1uEs09YHuVJn8CsrjV4bLnADNT/QbnVe20J4FSX4xqFm2f1\n87Ukp0XiomZLf11eekQ2MAoGCCqGSM49BAMCA0gAMEUCIEg1fDI8b3hZAArgniVk\nHeM6puwgcMh5NXwvJ9x0unVmAiEAppecVTSQ+yEPyBG415Og6sK+RC78pcByEC81\nC/QSwRYxggFpMIIBZQIBATAUMA8xDTALBgNVBAMMBGNlcnQCAQEwDQYJYIZIAWUD\nBAIBBQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUx\nDxcNMjUwNDAzMDAwMDAxWjAvBgkqhkiG9w0BCQQxIgQg7XACtDnprIRfIjV9gius\nFERzD722AW0+yUMil7nsn3MweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASow\nCwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0D\nAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwCgYI\nKoZIzj0EAwIESDBGAiEAssymc28HySAhg+XeWIpSbtzkwycr2JG6dzHRZ+vn0ocC\nIQCJVpo1FTLZOHSc9UpjS+VKR4cg50Iz0HiPyo6hwjCrwA==\n-----END PKCS7-----\n    EOF\n\n    cert = p7.certificates[0]\n    store = OpenSSL::X509::Store.new.tap { |store|\n      store.time = Time.utc(2025, 4, 3)\n      store.add_cert(cert)\n    }\n    assert_equal(true, p7.verify([], store))\n    assert_equal(1, p7.signers.size)\n    signer = p7.signers[0]\n    assert_in_delta(Time.utc(2025, 4, 3), signer.signed_time, 10)\n  end\n\n  def test_enveloped\n    omit_on_fips # PKCS #1 v1.5 padding\n\n    certs = [@ee1_cert, @ee2_cert]\n    cipher = OpenSSL::Cipher::AES.new(\"128-CBC\")\n    data = \"aaaaa\\nbbbbb\\nccccc\\n\"\n\n    tmp = OpenSSL::PKCS7.encrypt(certs, data, cipher, OpenSSL::PKCS7::BINARY)\n    p7 = OpenSSL::PKCS7.new(tmp.to_der)\n    recip = p7.recipients\n    assert_equal(:enveloped, p7.type)\n    assert_equal(2, recip.size)\n\n    assert_equal(@ca_cert.subject, recip[0].issuer)\n    assert_equal(@ee1_cert.serial, recip[0].serial)\n    assert_equal(16, @ee1_key.decrypt(recip[0].enc_key).size)\n    assert_equal(data, p7.decrypt(@ee1_key, @ee1_cert))\n\n    assert_equal(@ca_cert.subject, recip[1].issuer)\n    assert_equal(@ee2_cert.serial, recip[1].serial)\n    assert_equal(data, p7.decrypt(@ee2_key, @ee2_cert))\n\n    assert_equal(data, p7.decrypt(@ee1_key))\n\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) {\n      p7.decrypt(@ca_key, @ca_cert)\n    }\n\n    # Default cipher has been removed in v3.3\n    assert_raise_with_message(ArgumentError, /RC2-40-CBC/) {\n      OpenSSL::PKCS7.encrypt(certs, data)\n    }\n  end\n\n  def test_enveloped_add_recipient\n    omit_on_fips # PKCS #1 v1.5 padding\n\n    data = \"aaaaa\\nbbbbb\\nccccc\\n\"\n    ktri_ee1 = OpenSSL::PKCS7::RecipientInfo.new(@ee1_cert)\n    ktri_ee2 = OpenSSL::PKCS7::RecipientInfo.new(@ee2_cert)\n\n    tmp = OpenSSL::PKCS7.new\n    tmp.type = :enveloped\n    tmp.cipher = \"AES-128-CBC\"\n    tmp.add_recipient(ktri_ee1)\n    tmp.add_recipient(ktri_ee2)\n    tmp.add_data(data)\n\n    p7 = OpenSSL::PKCS7.new(tmp.to_der)\n    assert_equal(:enveloped, p7.type)\n    assert_equal(data, p7.decrypt(@ee1_key, @ee1_cert))\n    assert_equal(data, p7.decrypt(@ee2_key, @ee2_cert))\n    assert_equal([@ee1_cert.serial, @ee2_cert.serial].sort,\n                 p7.recipients.map(&:serial).sort)\n  end\n\n  def test_data\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::ObjectId(\"pkcs7-data\"),\n      OpenSSL::ASN1::OctetString(\"content\", 0, :EXPLICIT),\n    ])\n    p7 = OpenSSL::PKCS7.new\n    p7.type = :data\n    p7.data = \"content\"\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) { p7.add_certificate(@ee1_cert) }\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) { p7.certificates = [@ee1_cert] }\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) { p7.cipher = \"aes-128-cbc\" }\n    assert_equal(asn1.to_der, p7.to_der)\n\n    p7 = OpenSSL::PKCS7.new(asn1)\n    assert_equal(:data, p7.type)\n    assert_equal(false, p7.detached)\n    assert_equal(false, p7.detached?)\n    # Not applicable\n    assert_nil(p7.certificates)\n    assert_nil(p7.crls)\n    # Not applicable. Should they return nil or raise an exception instead?\n    assert_equal([], p7.signers)\n    assert_equal([], p7.recipients)\n    # PKCS7#verify can't distinguish verification failure and other errors\n    store = OpenSSL::X509::Store.new\n    assert_equal(false, p7.verify([@ee1_cert], store))\n    assert_match(/wrong content type|WRONG_CONTENT_TYPE/, p7.error_string)\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) { p7.decrypt(@ee1_key) }\n  end\n\n  def test_empty_signed_data_ruby_bug_19974\n    data = \"-----BEGIN PKCS7-----\\nMAsGCSqGSIb3DQEHAg==\\n-----END PKCS7-----\\n\"\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) { OpenSSL::PKCS7.new(data) }\n\n    data = <<END\nMIME-Version: 1.0\nContent-Disposition: attachment; filename=\"smime.p7m\"\nContent-Type: application/x-pkcs7-mime; smime-type=signed-data; name=\"smime.p7m\"\nContent-Transfer-Encoding: base64\n\n#{data}\nEND\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) { OpenSSL::PKCS7.read_smime(data) }\n  end\n\n  def test_graceful_parsing_failure #[ruby-core:43250]\n    contents = \"not a valid PKCS #7 PEM block\"\n    assert_raise(OpenSSL::PKCS7::PKCS7Error) { OpenSSL::PKCS7.new(contents) }\n  end\n\n  def test_set_type_signed\n    p7 = OpenSSL::PKCS7.new\n    p7.type = \"signed\"\n    assert_equal(:signed, p7.type)\n  end\n\n  def test_set_type_data\n    p7 = OpenSSL::PKCS7.new\n    p7.type = \"data\"\n    assert_equal(:data, p7.type)\n  end\n\n  def test_set_type_signed_and_enveloped\n    p7 = OpenSSL::PKCS7.new\n    p7.type = \"signedAndEnveloped\"\n    assert_equal(:signedAndEnveloped, p7.type)\n  end\n\n  def test_set_type_encrypted\n    p7 = OpenSSL::PKCS7.new\n    p7.type = \"encrypted\"\n    assert_equal(:encrypted, p7.type)\n  end\n\n  def test_smime\n    pend \"AWS-LC has no current support for SMIME with PKCS7\" if aws_lc?\n\n    store = OpenSSL::X509::Store.new\n    store.add_cert(@ca_cert)\n    ca_certs = [@ca_cert]\n\n    data = \"aaaaa\\r\\nbbbbb\\r\\nccccc\\r\\n\"\n    tmp = OpenSSL::PKCS7.sign(@ee1_cert, @ee1_key, data, ca_certs)\n    p7 = OpenSSL::PKCS7.new(tmp.to_der)\n    smime = OpenSSL::PKCS7.write_smime(p7)\n    assert_equal(true, smime.start_with?(<<END))\nMIME-Version: 1.0\nContent-Disposition: attachment; filename=\"smime.p7m\"\nContent-Type: application/x-pkcs7-mime; smime-type=signed-data; name=\"smime.p7m\"\nContent-Transfer-Encoding: base64\n\nEND\n    assert_equal(p7.to_der, OpenSSL::PKCS7.read_smime(smime).to_der)\n\n    smime = OpenSSL::PKCS7.write_smime(p7, nil, 0)\n    assert_equal(p7.to_der, OpenSSL::PKCS7.read_smime(smime).to_der)\n  end\n\n  def test_to_text\n    omit \"AWS-LC does not support PKCS7.to_text\" if aws_lc?\n\n    p7 = OpenSSL::PKCS7.new\n    p7.type = \"signed\"\n    assert_match(/signed/, p7.to_text)\n  end\n\n  def test_degenerate_pkcs7\n    ca_cert_pem = <<END\n-----BEGIN CERTIFICATE-----\nMIID4DCCAsigAwIBAgIJAL1oVI72wmQwMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV\nBAYTAkFVMQ4wDAYDVQQIEwVTdGF0ZTENMAsGA1UEBxMEQ2l0eTEQMA4GA1UEChMH\nRXhhbXBsZTETMBEGA1UEAxMKRXhhbXBsZSBDQTAeFw0xMjEwMTgwOTE2NTBaFw0y\nMjEwMTYwOTE2NTBaMFMxCzAJBgNVBAYTAkFVMQ4wDAYDVQQIEwVTdGF0ZTENMAsG\nA1UEBxMEQ2l0eTEQMA4GA1UEChMHRXhhbXBsZTETMBEGA1UEAxMKRXhhbXBsZSBD\nQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMTSPNxOkd5NN19XO0fJ\ntGVlWN4DWuvVL9WbWnXJXX9rU6X8sSOL9RrRA64eEZf2UBFjz9fMHZj/OGcxZpus\n4YtzfSrMU6xfvsIHeqX+mT60ms2RfX4UXab50MQArBin3JVKHGnOi25uyAOylVFU\nTuzzQJvKyB67vjuRPMlVAgVAZAP07ru9gW0ajt/ODxvUfvXxp5SFF68mVP2ipMBr\n4fujUwQC6cVHmnuL6p87VFoo9uk87TSQVDOQGL8MK4moMFtEW9oUTU22CgnxnCsS\nsCCELYhy9BdaTWQH26LzMfhnwSuIRHZyprW4WZtU0akrYXNiCj8o92rZmQWXJDbl\nqNECAwEAAaOBtjCBszAdBgNVHQ4EFgQUNtVw4jvkZZbkdQbkYi2/F4QN79owgYMG\nA1UdIwR8MHqAFDbVcOI75GWW5HUG5GItvxeEDe/aoVekVTBTMQswCQYDVQQGEwJB\nVTEOMAwGA1UECBMFU3RhdGUxDTALBgNVBAcTBENpdHkxEDAOBgNVBAoTB0V4YW1w\nbGUxEzARBgNVBAMTCkV4YW1wbGUgQ0GCCQC9aFSO9sJkMDAMBgNVHRMEBTADAQH/\nMA0GCSqGSIb3DQEBBQUAA4IBAQBvJIsY9bIqliZ3WD1KoN4cvAQeRAPsoLXQkkHg\nP6Nrcw9rJ5JvoHfYbo5aNlwbnkbt/B2xlVEXUYpJoBZFXafgxG2gJleioIgnaDS4\nFPPwZf1C5ZrOgUBfxTGjHex4ghSAoNGOd35jQzin5NGKOvZclPjZ2vQ++LP3aA2l\n9Fn2qASS46IzMGJlC75mlTOTQwDM16UunMAK26lNG9J6q02o4d/oU2a7x0fD80yF\n64kNA1wDAwaVCYiUH541qKp+b4iDqer8nf8HqzYDFlpje18xYZMEd1hj8dVOharM\npISJ+D52hV/BGEYF8r5k3hpC5d76gSP2oCcaY0XvLBf97qik\n-----END CERTIFICATE-----\nEND\n    p7 = OpenSSL::PKCS7.new\n    p7.type = \"signed\"\n    ca_cert = OpenSSL::X509::Certificate.new(ca_cert_pem)\n    p7.add_certificate ca_cert\n    p7.add_data \"\"\n\n    assert_nothing_raised do\n      p7.to_pem\n    end\n  end\n\n  def test_decode_ber_constructed_string\n    omit_on_fips # PKCS #1 v1.5 padding\n\n    p7 = OpenSSL::PKCS7.encrypt([@ee1_cert], \"content\", \"aes-128-cbc\")\n\n    # Make an equivalent BER to p7.to_der. Here we convert the encryptedContent\n    # field of EncryptedContentInfo into a constructed encoding using the\n    # indefinite length form.\n    # See https://www.rfc-editor.org/rfc/rfc2315#section-10.1\n    asn1 = OpenSSL::ASN1.decode(p7.to_der)\n    asn1.indefinite_length = true\n    enveloped_data_explicit_tag = asn1.value[1]\n    enveloped_data_explicit_tag.indefinite_length = true\n    enveloped_data = enveloped_data_explicit_tag.value[0]\n    enveloped_data.indefinite_length = true\n    encrypted_content_info = enveloped_data.value[2]\n    encrypted_content_info.indefinite_length = true\n    orig = encrypted_content_info.value[2]\n    encrypted_content_info.value[2] = OpenSSL::ASN1::ASN1Data.new([\n      OpenSSL::ASN1::OctetString(orig.value[...5]),\n      OpenSSL::ASN1::OctetString(orig.value[5...]),\n    ], 0, :CONTEXT_SPECIFIC).tap { |x| x.indefinite_length = true }\n\n    assert_not_equal(p7.to_der, asn1.to_der)\n    assert_equal(p7.to_der, OpenSSL::PKCS7.new(asn1.to_der).to_der)\n\n    assert_equal(\"content\", OpenSSL::PKCS7.new(p7.to_der).decrypt(@ee1_key))\n    assert_equal(\"content\", OpenSSL::PKCS7.new(asn1.to_der).decrypt(@ee1_key))\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_pkey.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nclass OpenSSL::TestPKey < OpenSSL::PKeyTestCase\n  def test_generic_oid_inspect_rsa\n    # RSA private key\n    rsa = Fixtures.pkey(\"rsa-1\")\n    assert_instance_of OpenSSL::PKey::RSA, rsa\n    assert_equal \"rsaEncryption\", rsa.oid\n    assert_match %r{oid=rsaEncryption}, rsa.inspect\n    assert_match %r{type_name=RSA}, rsa.inspect if openssl?(3, 0, 0)\n  end\n\n  def test_s_generate_parameters\n    pkey = OpenSSL::PKey.generate_parameters(\"EC\", {\n      \"ec_paramgen_curve\" => \"secp384r1\",\n    })\n    assert_instance_of OpenSSL::PKey::EC, pkey\n    assert_equal \"secp384r1\", pkey.group.curve_name\n    assert_equal nil, pkey.private_key\n\n    # Invalid options are checked\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      OpenSSL::PKey.generate_parameters(\"EC\", \"invalid\" => \"option\")\n    }\n  end\n\n  def test_s_generate_parameters_with_block\n    # DSA kengen is not FIPS-approved.\n    # https://github.com/openssl/openssl/commit/49a35f0#diff-605396c063194975af8ce31399d42690ab18186b422fb5012101cc9132660fe1R611-R614\n    omit_on_fips\n\n    # Parameter generation callback is called\n    if openssl?(3, 0, 0, 0) && !openssl?(3, 0, 0, 6)\n      # Errors in BN_GENCB were not properly handled. This special pend is to\n      # suppress failures on Ubuntu 22.04, which uses OpenSSL 3.0.2.\n      pend \"unstable test on OpenSSL 3.0.[0-5]\"\n    end\n    cb_called = []\n    assert_raise(RuntimeError) {\n      OpenSSL::PKey.generate_parameters(\"DSA\") { |*args|\n        cb_called << args\n        raise \"exit!\" if cb_called.size == 3\n      }\n    }\n    assert_not_empty cb_called\n  end\n\n  def test_s_generate_key\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      # DSA key pair cannot be generated without parameters\n      OpenSSL::PKey.generate_key(\"DSA\")\n    }\n    pkey_params = OpenSSL::PKey.generate_parameters(\"EC\", {\n      \"ec_paramgen_curve\" => \"secp384r1\",\n    })\n    pkey = OpenSSL::PKey.generate_key(pkey_params)\n    assert_instance_of OpenSSL::PKey::EC, pkey\n    assert_equal \"secp384r1\", pkey.group.curve_name\n    assert_not_equal nil, pkey.private_key\n  end\n\n  def test_s_read_pem_unknown_block\n    # A PEM-encoded certificate and a PEM-encoded private key are combined.\n    # Check that OSSL_STORE doesn't stop after the first PEM block.\n    orig = Fixtures.pkey(\"rsa-1\")\n    subject = OpenSSL::X509::Name.new([[\"CN\", \"test\"]])\n    cert = issue_cert(subject, orig, 1, [], nil, nil)\n\n    input = cert.to_text + cert.to_pem + orig.to_text + orig.private_to_pem\n    pkey = OpenSSL::PKey.read(input)\n    assert_equal(orig.private_to_der, pkey.private_to_der)\n  end\n\n  def test_s_read_der_then_pem\n    # If the input is valid as both DER and PEM (which allows garbage data\n    # before and after the block), it is read as DER\n    #\n    # TODO: Garbage data after DER should not be allowed, but it is currently\n    # ignored\n    orig1 = Fixtures.pkey(\"rsa-1\")\n    orig2 = Fixtures.pkey(\"rsa-2\")\n    pkey = OpenSSL::PKey.read(orig1.public_to_der + orig2.private_to_pem)\n    assert_equal(orig1.public_to_der, pkey.public_to_der)\n    assert_not_predicate(pkey, :private?)\n  end\n\n  def test_s_read_passphrase\n    orig = Fixtures.pkey(\"rsa-1\")\n    encrypted_pem = orig.private_to_pem(\"AES-256-CBC\", \"correct_passphrase\")\n    assert_match(/\\A-----BEGIN ENCRYPTED PRIVATE KEY-----/, encrypted_pem)\n\n    # Correct passphrase passed as the second argument\n    pkey1 = OpenSSL::PKey.read(encrypted_pem, \"correct_passphrase\")\n    assert_equal(orig.private_to_der, pkey1.private_to_der)\n\n    # Correct passphrase returned by the block. The block gets false\n    called = 0\n    flag = nil\n    pkey2 = OpenSSL::PKey.read(encrypted_pem) { |f|\n      called += 1\n      flag = f\n      \"correct_passphrase\"\n    }\n    assert_equal(orig.private_to_der, pkey2.private_to_der)\n    assert_equal(1, called)\n    assert_false(flag)\n\n    # Incorrect passphrase passed. The block is not called\n    called = 0\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      OpenSSL::PKey.read(encrypted_pem, \"incorrect_passphrase\") {\n        called += 1\n      }\n    }\n    assert_equal(0, called)\n\n    # Incorrect passphrase returned by the block. The block is called only once\n    called = 0\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      OpenSSL::PKey.read(encrypted_pem) {\n        called += 1\n        \"incorrect_passphrase\"\n      }\n    }\n    assert_equal(1, called)\n  end\n\n  def test_s_read_passphrase_tty\n    omit \"https://github.com/aws/aws-lc/pull/2555\" if aws_lc?\n\n    orig = Fixtures.pkey(\"rsa-1\")\n    encrypted_pem = orig.private_to_pem(\"AES-256-CBC\", \"correct_passphrase\")\n\n    # Correct passphrase passed to OpenSSL's prompt\n    script = <<~\"end;\"\n      require \"openssl\"\n      Process.setsid\n      OpenSSL::PKey.read(#{encrypted_pem.dump})\n      puts \"ok\"\n    end;\n    assert_in_out_err([*$:.map { |l| \"-I#{l}\" }, \"-e#{script}\"],\n                      \"correct_passphrase\\n\") { |stdout, stderr|\n      assert_equal([\"Enter PEM pass phrase:\"], stderr)\n      assert_equal([\"ok\"], stdout)\n    }\n\n    # Incorrect passphrase passed to OpenSSL's prompt\n    script = <<~\"end;\"\n      require \"openssl\"\n      Process.setsid\n      begin\n        OpenSSL::PKey.read(#{encrypted_pem.dump})\n      rescue OpenSSL::PKey::PKeyError\n        puts \"ok\"\n      else\n        puts \"expected OpenSSL::PKey::PKeyError\"\n      end\n    end;\n    stdin = \"incorrect_passphrase\\n\" * 5\n    assert_in_out_err([*$:.map { |l| \"-I#{l}\" }, \"-e#{script}\"],\n                      stdin) { |stdout, stderr|\n      assert_equal(1, stderr.count(\"Enter PEM pass phrase:\"))\n      assert_equal([\"ok\"], stdout)\n    }\n  end if ENV[\"OSSL_TEST_ALL\"] == \"1\" && Process.respond_to?(:setsid)\n\n  def test_hmac_sign_verify\n    pkey = OpenSSL::PKey.generate_key(\"HMAC\", { \"key\" => \"abcd\" })\n\n    hmac = OpenSSL::HMAC.new(\"abcd\", \"SHA256\").update(\"data\").digest\n    assert_equal hmac, pkey.sign(\"SHA256\", \"data\")\n\n    # EVP_PKEY_HMAC does not support verify\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      pkey.verify(\"SHA256\", \"data\", hmac)\n    }\n  end\n\n  def test_ed25519\n    # Ed25519 is not FIPS-approved.\n    omit_on_fips\n\n    # Test vector from RFC 8032 Section 7.1 TEST 2\n    priv_pem = <<~EOF\n    -----BEGIN PRIVATE KEY-----\n    MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7\n    -----END PRIVATE KEY-----\n    EOF\n    pub_pem = <<~EOF\n    -----BEGIN PUBLIC KEY-----\n    MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw=\n    -----END PUBLIC KEY-----\n    EOF\n    priv = OpenSSL::PKey.read(priv_pem)\n    pub = OpenSSL::PKey.read(pub_pem)\n    assert_instance_of OpenSSL::PKey::PKey, priv\n    assert_instance_of OpenSSL::PKey::PKey, pub\n    assert_equal priv_pem, priv.private_to_pem\n    assert_equal pub_pem, priv.public_to_pem\n    assert_equal pub_pem, pub.public_to_pem\n\n    assert_equal \"4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb\",\n      priv.raw_private_key.unpack1(\"H*\")\n    assert_equal OpenSSL::PKey.new_raw_private_key(\"ED25519\", priv.raw_private_key).private_to_pem,\n      priv.private_to_pem\n    assert_equal \"3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c\",\n      priv.raw_public_key.unpack1(\"H*\")\n    assert_equal OpenSSL::PKey.new_raw_public_key(\"ED25519\", priv.raw_public_key).public_to_pem,\n      pub.public_to_pem\n\n    sig = [<<~EOF.gsub(/[^0-9a-f]/, \"\")].pack(\"H*\")\n    92a009a9f0d4cab8720e820b5f642540\n    a2b27b5416503f8fb3762223ebdb69da\n    085ac1e43e15996e458f3613d0f11d8c\n    387b2eaeb4302aeeb00d291612bb0c00\n    EOF\n    data = [\"72\"].pack(\"H*\")\n    assert_equal sig, priv.sign(nil, data)\n    assert_equal true, priv.verify(nil, sig, data)\n    assert_equal true, pub.verify(nil, sig, data)\n    assert_equal false, pub.verify(nil, sig, data.succ)\n\n    # PureEdDSA wants nil as the message digest\n    assert_raise(OpenSSL::PKey::PKeyError) { priv.sign(\"SHA512\", data) }\n    assert_raise(OpenSSL::PKey::PKeyError) { pub.verify(\"SHA512\", sig, data) }\n\n    # Ed25519 pkey type does not support key derivation\n    assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) }\n  end\n\n  def test_x25519\n    omit_on_fips\n\n    # Test vector from RFC 7748 Section 6.1\n    alice_pem = <<~EOF\n    -----BEGIN PRIVATE KEY-----\n    MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq\n    -----END PRIVATE KEY-----\n    EOF\n    bob_pem = <<~EOF\n    -----BEGIN PUBLIC KEY-----\n    MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08=\n    -----END PUBLIC KEY-----\n    EOF\n    shared_secret = \"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742\"\n\n    alice = OpenSSL::PKey.read(alice_pem)\n    bob = OpenSSL::PKey.read(bob_pem)\n    assert_instance_of OpenSSL::PKey::PKey, alice\n    assert_equal \"X25519\", alice.oid\n    assert_match %r{oid=X25519}, alice.inspect\n    assert_equal alice_pem, alice.private_to_pem\n    assert_equal bob_pem, bob.public_to_pem\n    assert_equal [shared_secret].pack(\"H*\"), alice.derive(bob)\n\n    alice_private = OpenSSL::PKey.new_raw_private_key(\"X25519\", alice.raw_private_key)\n    bob_public = OpenSSL::PKey.new_raw_public_key(\"X25519\", bob.raw_public_key)\n    assert_equal alice_private.private_to_pem,\n      alice.private_to_pem\n    assert_equal bob_public.public_to_pem,\n      bob.public_to_pem\n    assert_equal \"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a\",\n      alice.raw_private_key.unpack1(\"H*\")\n    assert_equal \"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f\",\n      bob.raw_public_key.unpack1(\"H*\")\n  end\n\n  def test_ml_dsa\n    # AWS-LC also supports ML-DSA, but it's implemented in a different way\n    return unless openssl?(3, 5, 0)\n\n    pkey = OpenSSL::PKey.generate_key(\"ML-DSA-44\")\n    assert_match(/type_name=ML-DSA-44/, pkey.inspect)\n    sig = pkey.sign(nil, \"data\")\n    assert_equal(2420, sig.bytesize)\n    assert_equal(true, pkey.verify(nil, sig, \"data\"))\n\n    pub2 = OpenSSL::PKey.read(pkey.public_to_der)\n    assert_equal(true, pub2.verify(nil, sig, \"data\"))\n\n    raw_public_key = pkey.raw_public_key\n    assert_equal(1312, raw_public_key.bytesize)\n    pub3 = OpenSSL::PKey.new_raw_public_key(\"ML-DSA-44\", raw_public_key)\n    assert_equal(true, pub3.verify(nil, sig, \"data\"))\n  end\n\n  def test_raw_initialize_errors\n    assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key(\"foo123\", \"xxx\") }\n    assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key(\"ED25519\", \"xxx\") }\n    assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key(\"foo123\", \"xxx\") }\n    assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key(\"ED25519\", \"xxx\") }\n  end\n\n  def test_compare?\n    key1 = Fixtures.pkey(\"rsa-1\")\n    key2 = Fixtures.pkey(\"rsa-1\")\n    key3 = Fixtures.pkey(\"rsa-2\")\n    key4 = Fixtures.pkey(\"p256\")\n\n    assert_equal(true, key1.compare?(key2))\n    assert_equal(true, key1.public_key.compare?(key2))\n    assert_equal(true, key2.compare?(key1))\n    assert_equal(true, key2.public_key.compare?(key1))\n\n    assert_equal(false, key1.compare?(key3))\n\n    assert_raise(TypeError) do\n      key1.compare?(key4)\n    end\n  end\n\n  def test_to_text\n    rsa = Fixtures.pkey(\"rsa-1\")\n    assert_include rsa.to_text, \"publicExponent\"\n  end\n\n  def test_legacy_error_classes\n    assert_same(OpenSSL::PKey::PKeyError, OpenSSL::PKey::DSAError)\n    assert_same(OpenSSL::PKey::PKeyError, OpenSSL::PKey::DHError)\n    assert_same(OpenSSL::PKey::PKeyError, OpenSSL::PKey::ECError)\n    assert_same(OpenSSL::PKey::PKeyError, OpenSSL::PKey::RSAError)\n  end\nend\n"
  },
  {
    "path": "test/openssl/test_pkey_dh.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL) && defined?(OpenSSL::PKey::DH)\n\nclass OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase\n  def test_new_empty\n    # pkeys are immutable with OpenSSL >= 3.0\n    if openssl?(3, 0, 0)\n      assert_raise(ArgumentError) { OpenSSL::PKey::DH.new }\n    else\n      dh = OpenSSL::PKey::DH.new\n      assert_nil(dh.p)\n      assert_nil(dh.priv_key)\n    end\n  end\n\n  def test_new_generate\n    begin\n      dh1 = OpenSSL::PKey::DH.new(512)\n    rescue OpenSSL::PKey::PKeyError\n      omit \"generating 512-bit DH parameters failed; \" \\\n        \"likely not supported by this OpenSSL build\"\n    end\n    assert_equal(512, dh1.p.num_bits)\n    assert_key(dh1)\n\n    dh2 = OpenSSL::PKey::DH.generate(512)\n    assert_equal(512, dh2.p.num_bits)\n    assert_key(dh2)\n    assert_not_equal(dh1.p, dh2.p)\n  end if ENV[\"OSSL_TEST_ALL\"] == \"1\"\n\n  def test_new_break\n    unless openssl? && OpenSSL.fips_mode\n      assert_raise(RuntimeError) do\n        OpenSSL::PKey::DH.new(2048) { raise }\n      end\n    else\n      # The block argument is not executed in FIPS case.\n      # See https://github.com/ruby/openssl/issues/692 for details.\n      assert_kind_of(OpenSSL::PKey::DH, OpenSSL::PKey::DH.new(2048) { raise })\n    end\n  end\n\n  def test_derive_key\n    params = Fixtures.pkey(\"dh2048_ffdhe2048\")\n    dh1 = OpenSSL::PKey.generate_key(params)\n    dh2 = OpenSSL::PKey.generate_key(params)\n    dh1_pub = OpenSSL::PKey.read(dh1.public_to_der)\n    dh2_pub = OpenSSL::PKey.read(dh2.public_to_der)\n\n    z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2)\n    assert_equal z, dh1.derive(dh2_pub)\n    assert_equal z, dh2.derive(dh1_pub)\n\n    assert_raise(OpenSSL::PKey::PKeyError) { params.derive(dh1_pub) }\n    assert_raise(OpenSSL::PKey::PKeyError) { dh1_pub.derive(params) }\n\n    assert_equal z, dh1.compute_key(dh2.pub_key)\n    assert_equal z, dh2.compute_key(dh1.pub_key)\n  end\n\n  def test_DHparams\n    dh_params = Fixtures.pkey(\"dh2048_ffdhe2048\")\n\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Integer(dh_params.p),\n      OpenSSL::ASN1::Integer(dh_params.g)\n    ])\n    assert_equal(asn1.to_der, dh_params.to_der)\n    key = OpenSSL::PKey::DH.new(asn1.to_der)\n    assert_same_dh_params(dh_params, key)\n\n    pem = <<~EOF\n    -----BEGIN DH PARAMETERS-----\n    MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n    +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n    87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n    YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n    7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n    ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==\n    -----END DH PARAMETERS-----\n    EOF\n    assert_equal(pem, dh_params.export)\n\n    key = OpenSSL::PKey::DH.new(pem)\n    assert_same_dh_params(dh_params, key)\n    assert_no_key(key)\n    key = OpenSSL::PKey.read(pem)\n    assert_same_dh_params(dh_params, key)\n    assert_no_key(key)\n\n    key = OpenSSL::PKey.generate_key(dh_params)\n    assert_same_dh_params(dh_params, key)\n    assert_key(key)\n    assert_equal(dh_params.to_der, key.to_der)\n    assert_equal(dh_params.to_pem, key.to_pem)\n  end\n\n  def test_public_key\n    dh = Fixtures.pkey(\"dh2048_ffdhe2048\")\n    public_key = dh.public_key\n    assert_no_key(public_key) #implies public_key.public? is false!\n    assert_equal(dh.to_der, public_key.to_der)\n    assert_equal(dh.to_pem, public_key.to_pem)\n  end\n\n  def test_generate_key\n    # Deprecated in v3.0.0; incompatible with OpenSSL 3.0\n    dh = Fixtures.pkey(\"dh2048_ffdhe2048\")\n    assert_no_key(dh)\n    dh.generate_key!\n    assert_key(dh)\n\n    dh2 = OpenSSL::PKey::DH.new(dh.to_der)\n    dh2.generate_key!\n    assert_not_equal(dh.pub_key, dh2.pub_key)\n    assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key))\n  end if !openssl?(3, 0, 0)\n\n  def test_params_ok?\n    omit_on_fips\n\n    # Skip the tests in old OpenSSL version 1.1.1c or early versions before\n    # applying the following commits in OpenSSL 1.1.1d to make `DH_check`\n    # function pass the RFC 7919 FFDHE group texts.\n    # https://github.com/openssl/openssl/pull/9435\n    if openssl? && !openssl?(1, 1, 1, 4)\n      pend 'DH check for RFC 7919 FFDHE group texts is not implemented'\n    end\n\n    dh0 = Fixtures.pkey(\"dh2048_ffdhe2048\")\n\n    dh1 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Integer(dh0.p),\n      OpenSSL::ASN1::Integer(dh0.g)\n    ]))\n    assert_equal(true, dh1.params_ok?)\n\n    # AWS-LC automatically does parameter checks on the parsed params.\n    if aws_lc?\n      assert_raise(OpenSSL::PKey::PKeyError) {\n        OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([\n          OpenSSL::ASN1::Integer(dh0.p + 1),\n          OpenSSL::ASN1::Integer(dh0.g)\n        ]))\n      }\n    else\n      dh2 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([\n        OpenSSL::ASN1::Integer(dh0.p + 1),\n        OpenSSL::ASN1::Integer(dh0.g)\n      ]))\n      assert_equal(false, dh2.params_ok?)\n    end\n\n  end\n\n  def test_params\n    dh = Fixtures.pkey(\"dh2048_ffdhe2048\")\n    assert_kind_of(OpenSSL::BN, dh.p)\n    assert_equal(dh.p, dh.params[\"p\"])\n    assert_kind_of(OpenSSL::BN, dh.g)\n    assert_equal(dh.g, dh.params[\"g\"])\n    assert_nil(dh.pub_key)\n    assert_nil(dh.params[\"pub_key\"])\n    assert_nil(dh.priv_key)\n    assert_nil(dh.params[\"priv_key\"])\n\n    dhkey = OpenSSL::PKey.generate_key(dh)\n    assert_equal(dh.params[\"p\"], dhkey.params[\"p\"])\n    assert_kind_of(OpenSSL::BN, dhkey.pub_key)\n    assert_equal(dhkey.pub_key, dhkey.params[\"pub_key\"])\n    assert_kind_of(OpenSSL::BN, dhkey.priv_key)\n    assert_equal(dhkey.priv_key, dhkey.params[\"priv_key\"])\n  end\n\n  def test_dup\n    # Parameters only\n    dh1 = Fixtures.pkey(\"dh2048_ffdhe2048\")\n    dh2 = dh1.dup\n    assert_equal dh1.to_der, dh2.to_der\n    assert_not_equal nil, dh1.p\n    assert_not_equal nil, dh1.g\n    assert_equal [dh1.p, dh1.g], [dh2.p, dh2.g]\n    assert_equal nil, dh1.pub_key\n    assert_equal nil, dh1.priv_key\n    assert_equal [dh1.pub_key, dh1.priv_key], [dh2.pub_key, dh2.priv_key]\n\n    # PKey is immutable in OpenSSL >= 3.0\n    if !openssl?(3, 0, 0)\n      dh2.set_pqg(dh2.p + 1, nil, dh2.g)\n      assert_not_equal dh2.p, dh1.p\n    end\n\n    # With a key pair\n    dh3 = OpenSSL::PKey.generate_key(Fixtures.pkey(\"dh2048_ffdhe2048\"))\n    dh4 = dh3.dup\n    assert_equal dh3.to_der, dh4.to_der\n    assert_equal dh1.to_der, dh4.to_der # encodes parameters only\n    assert_equal [dh1.p, dh1.g], [dh4.p, dh4.g]\n    assert_not_equal nil, dh3.pub_key\n    assert_not_equal nil, dh3.priv_key\n    assert_equal [dh3.pub_key, dh3.priv_key], [dh4.pub_key, dh4.priv_key]\n  end\n\n  def test_marshal\n    dh = Fixtures.pkey(\"dh2048_ffdhe2048\")\n    deserialized = Marshal.load(Marshal.dump(dh))\n\n    assert_equal dh.to_der, deserialized.to_der\n  end\n\n  private\n\n  def assert_no_key(dh)\n    assert_equal(false, dh.public?)\n    assert_equal(false, dh.private?)\n    assert_equal(nil, dh.pub_key)\n    assert_equal(nil, dh.priv_key)\n  end\n\n  def assert_key(dh)\n    assert_true(dh.public?)\n    assert_true(dh.private?)\n    assert_kind_of(OpenSSL::BN, dh.pub_key)\n    assert_kind_of(OpenSSL::BN, dh.priv_key)\n  end\n\n  def assert_same_dh_params(expected, key)\n    check_component(expected, key, [:p, :q, :g])\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_pkey_dsa.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL) && defined?(OpenSSL::PKey::DSA)\n\nclass OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase\n  def setup\n    # May not be available in FIPS mode as DSA has been deprecated in FIPS 186-5\n    omit_on_fips\n  end\n\n  def test_private\n    key = Fixtures.pkey(\"dsa2048\")\n    assert_equal true, key.private?\n    key2 = OpenSSL::PKey::DSA.new(key.to_der)\n    assert_equal true, key2.private?\n    key3 = key.public_key\n    assert_equal false, key3.private?\n    key4 = OpenSSL::PKey::DSA.new(key3.to_der)\n    assert_equal false, key4.private?\n  end\n\n  def test_new\n    key = OpenSSL::PKey::DSA.new(2048)\n    pem  = key.public_key.to_pem\n    OpenSSL::PKey::DSA.new pem\n  end\n\n  def test_new_break\n    assert_nil(OpenSSL::PKey::DSA.new(2048) { break })\n    assert_raise(RuntimeError) do\n      OpenSSL::PKey::DSA.new(2048) { raise }\n    end\n  end\n\n  def test_new_empty\n    # pkeys are immutable with OpenSSL >= 3.0\n    if openssl?(3, 0, 0)\n      assert_raise(ArgumentError) { OpenSSL::PKey::DSA.new }\n    else\n      key = OpenSSL::PKey::DSA.new\n      assert_nil(key.p)\n      assert_raise(OpenSSL::PKey::PKeyError) { key.to_der }\n    end\n  end\n\n  def test_generate\n    # DSA.generate used to call DSA_generate_parameters_ex(), which adjusts the\n    # size of q according to the size of p\n    key1024 = OpenSSL::PKey::DSA.generate(1024)\n    assert_predicate key1024, :private?\n    assert_equal 1024, key1024.p.num_bits\n    assert_equal 160, key1024.q.num_bits\n\n    if ENV[\"OSSL_TEST_ALL\"] == \"1\" # slow\n      key2048 = OpenSSL::PKey::DSA.generate(2048)\n      assert_equal 2048, key2048.p.num_bits\n      assert_equal 256, key2048.q.num_bits\n\n      key3072 = OpenSSL::PKey::DSA.generate(3072)\n      assert_equal 3072, key3072.p.num_bits\n      assert_equal 256, key3072.q.num_bits\n    end\n  end\n\n  def test_sign_verify\n    # The DSA valid size is 2048 or 3072 on FIPS.\n    # https://github.com/openssl/openssl/blob/7649b5548e5c0352b91d9d3ed695e42a2ac1e99c/providers/common/securitycheck.c#L185-L188\n    dsa = Fixtures.pkey(\"dsa2048\")\n    data = \"Sign me!\"\n    if defined?(OpenSSL::Digest::DSS1)\n      signature = dsa.sign(OpenSSL::Digest.new('DSS1'), data)\n      assert_equal true, dsa.verify(OpenSSL::Digest.new('DSS1'), signature, data)\n    end\n\n    signature = dsa.sign(\"SHA256\", data)\n    assert_equal true, dsa.verify(\"SHA256\", signature, data)\n\n    signature0 = (<<~'end;').unpack1(\"m\")\n      MD4CHQC0zmRkVOAHJTm28fS5PVUv+4LtBeNaKqr/yfmVAh0AsTcLqofWHoW8X5oWu8AOvngOcFVZ\n      cLTvhY3XNw==\n    end;\n    assert_equal true, dsa.verify(\"SHA256\", signature0, data)\n    signature1 = signature0.succ\n    assert_equal false, dsa.verify(\"SHA256\", signature1, data)\n  end\n\n  def test_sign_verify_raw\n    key = Fixtures.pkey(\"dsa2048\")\n    data = 'Sign me!'\n    digest = OpenSSL::Digest.digest('SHA1', data)\n\n    invalid_sig = key.sign_raw(nil, digest.succ)\n    malformed_sig = \"*\" * invalid_sig.bytesize\n\n    # Sign by #syssign\n    sig = key.syssign(digest)\n    assert_equal true, key.sysverify(digest, sig)\n    assert_equal false, key.sysverify(digest, invalid_sig)\n    assert_sign_verify_false_or_error { key.sysverify(digest, malformed_sig) }\n    assert_equal true, key.verify_raw(nil, sig, digest)\n    assert_equal false, key.verify_raw(nil, invalid_sig, digest)\n    assert_sign_verify_false_or_error { key.verify_raw(nil, malformed_sig, digest) }\n\n    # Sign by #sign_raw\n    sig = key.sign_raw(nil, digest)\n    assert_equal true, key.sysverify(digest, sig)\n    assert_equal false, key.sysverify(digest, invalid_sig)\n    assert_sign_verify_false_or_error { key.sysverify(digest, malformed_sig) }\n    assert_equal true, key.verify_raw(nil, sig, digest)\n    assert_equal false, key.verify_raw(nil, invalid_sig, digest)\n    assert_sign_verify_false_or_error { key.verify_raw(nil, malformed_sig, digest) }\n  end\n\n  def test_DSAPrivateKey\n    # OpenSSL DSAPrivateKey format; similar to RSAPrivateKey\n    orig = Fixtures.pkey(\"dsa2048\")\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Integer(0),\n      OpenSSL::ASN1::Integer(orig.p),\n      OpenSSL::ASN1::Integer(orig.q),\n      OpenSSL::ASN1::Integer(orig.g),\n      OpenSSL::ASN1::Integer(orig.pub_key),\n      OpenSSL::ASN1::Integer(orig.priv_key)\n    ])\n    key = OpenSSL::PKey::DSA.new(asn1.to_der)\n    assert_predicate key, :private?\n    assert_same_dsa orig, key\n\n    pem = der_to_pem(asn1.to_der, \"DSA PRIVATE KEY\")\n    key = OpenSSL::PKey::DSA.new(pem)\n    assert_same_dsa orig, key\n\n    assert_equal asn1.to_der, orig.to_der\n    assert_equal pem, orig.export\n  end\n\n  def test_DSAPrivateKey_encrypted\n    # OpenSSL DSAPrivateKey with OpenSSL encryption\n    orig = Fixtures.pkey(\"dsa2048\")\n\n    pem = der_to_encrypted_pem(orig.to_der, \"DSA PRIVATE KEY\", \"abcdef\")\n    key = OpenSSL::PKey::DSA.new(pem, \"abcdef\")\n    assert_same_dsa orig, key\n    key = OpenSSL::PKey::DSA.new(pem) { \"abcdef\" }\n    assert_same_dsa orig, key\n\n    cipher = OpenSSL::Cipher.new(\"aes-128-cbc\")\n    exported = orig.to_pem(cipher, \"abcdef\\0\\1\")\n    assert_same_dsa orig, OpenSSL::PKey::DSA.new(exported, \"abcdef\\0\\1\")\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      OpenSSL::PKey::DSA.new(exported, \"abcdef\")\n    }\n  end\n\n  def test_PUBKEY\n    orig = Fixtures.pkey(\"dsa2048\")\n    pub = OpenSSL::PKey::DSA.new(orig.public_to_der)\n\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Sequence([\n        OpenSSL::ASN1::ObjectId(\"DSA\"),\n        OpenSSL::ASN1::Sequence([\n          OpenSSL::ASN1::Integer(orig.p),\n          OpenSSL::ASN1::Integer(orig.q),\n          OpenSSL::ASN1::Integer(orig.g)\n        ])\n      ]),\n      OpenSSL::ASN1::BitString(\n        OpenSSL::ASN1::Integer(orig.pub_key).to_der\n      )\n    ])\n    key = OpenSSL::PKey::DSA.new(asn1.to_der)\n    assert_not_predicate key, :private?\n    assert_same_dsa pub, key\n\n    pem = der_to_pem(asn1.to_der, \"PUBLIC KEY\")\n    key = OpenSSL::PKey::DSA.new(pem)\n    assert_same_dsa pub, key\n\n    assert_equal asn1.to_der, key.to_der\n    assert_equal pem, key.export\n\n    assert_equal asn1.to_der, orig.public_to_der\n    assert_equal asn1.to_der, key.public_to_der\n    assert_equal pem, orig.public_to_pem\n    assert_equal pem, key.public_to_pem\n  end\n\n  def test_read_DSAPublicKey_pem\n    # TODO: where is the standard? PKey::DSA.new can read only PEM\n    p = 12260055936871293565827712385212529106400444521449663325576634579961635627321079536132296996623400607469624537382977152381984332395192110731059176842635699\n    q = 979494906553787301107832405790107343409973851677\n    g = 3731695366899846297271147240305742456317979984190506040697507048095553842519347835107669437969086119948785140453492839427038591924536131566350847469993845\n    y = 10505239074982761504240823422422813362721498896040719759460296306305851824586095328615844661273887569281276387605297130014564808567159023649684010036304695\n    pem = <<-EOF\n-----BEGIN DSA PUBLIC KEY-----\nMIHfAkEAyJSJ+g+P/knVcgDwwTzC7Pwg/pWs2EMd/r+lYlXhNfzg0biuXRul8VR4\nVUC/phySExY0PdcqItkR/xYAYNMbNwJBAOoV57X0FxKO/PrNa/MkoWzkCKV/hzhE\np0zbFdsicw+hIjJ7S6Sd/FlDlo89HQZ2FuvWJ6wGLM1j00r39+F2qbMCFQCrkhIX\nSG+is37hz1IaBeEudjB2HQJAR0AloavBvtsng8obsjLb7EKnB+pSeHr/BdIQ3VH7\nfWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ==\n-----END DSA PUBLIC KEY-----\n    EOF\n    key = OpenSSL::PKey::DSA.new(pem)\n    assert(key.public?)\n    assert(!key.private?)\n    assert_equal(p, key.p)\n    assert_equal(q, key.q)\n    assert_equal(g, key.g)\n    assert_equal(y, key.pub_key)\n    assert_equal(nil, key.priv_key)\n  end\n\n  def test_params\n    key = Fixtures.pkey(\"dsa2048\")\n    assert_kind_of(OpenSSL::BN, key.p)\n    assert_equal(key.p, key.params[\"p\"])\n    assert_kind_of(OpenSSL::BN, key.q)\n    assert_equal(key.q, key.params[\"q\"])\n    assert_kind_of(OpenSSL::BN, key.g)\n    assert_equal(key.g, key.params[\"g\"])\n    assert_kind_of(OpenSSL::BN, key.pub_key)\n    assert_equal(key.pub_key, key.params[\"pub_key\"])\n    assert_kind_of(OpenSSL::BN, key.priv_key)\n    assert_equal(key.priv_key, key.params[\"priv_key\"])\n\n    pubkey = OpenSSL::PKey.read(key.public_to_der)\n    assert_equal(key.params[\"p\"], pubkey.params[\"p\"])\n    assert_equal(key.pub_key, pubkey.pub_key)\n    assert_equal(key.pub_key, pubkey.params[\"pub_key\"])\n    assert_nil(pubkey.priv_key)\n    assert_nil(pubkey.params[\"priv_key\"])\n  end\n\n  def test_dup\n    key = Fixtures.pkey(\"dsa2048\")\n    key2 = key.dup\n    assert_equal key.params, key2.params\n\n    # PKey is immutable in OpenSSL >= 3.0\n    if !openssl?(3, 0, 0)\n      key2.set_pqg(key2.p + 1, key2.q, key2.g)\n      assert_not_equal key.params, key2.params\n    end\n  end\n\n  def test_marshal\n    key = Fixtures.pkey(\"dsa2048\")\n    deserialized = Marshal.load(Marshal.dump(key))\n\n    assert_equal key.to_der, deserialized.to_der\n  end\n\n  private\n  def assert_same_dsa(expected, key)\n    check_component(expected, key, [:p, :q, :g, :pub_key, :priv_key])\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_pkey_ec.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestEC < OpenSSL::PKeyTestCase\n  def test_ec_key_new\n    key1 = OpenSSL::PKey::EC.generate(\"prime256v1\")\n\n    key3 = OpenSSL::PKey::EC.new(key1)\n    assert_equal key1.to_der, key3.to_der\n\n    key4 = OpenSSL::PKey::EC.new(key1.to_der)\n    assert_equal key1.to_der, key4.to_der\n\n    key5 = key1.dup\n    assert_equal key1.to_der, key5.to_der\n\n    # PKey is immutable in OpenSSL >= 3.0; EC object should not be modified\n    if !openssl?(3, 0, 0)\n      key_tmp = OpenSSL::PKey::EC.generate(\"prime256v1\")\n      key5.private_key = key_tmp.private_key\n      key5.public_key = key_tmp.public_key\n      assert_not_equal key1.to_der, key5.to_der\n    end\n  end\n\n  def test_ec_key_new_empty\n    # pkeys are immutable with OpenSSL >= 3.0; constructing an empty EC object is\n    # disallowed\n    if openssl?(3, 0, 0)\n      assert_raise(ArgumentError) { OpenSSL::PKey::EC.new }\n    else\n      key = OpenSSL::PKey::EC.new\n      assert_nil(key.group)\n\n      p256 = Fixtures.pkey(\"p256\")\n      key.group = p256.group\n      key.private_key = p256.private_key\n      key.public_key = p256.public_key\n      assert_equal(p256.to_der, key.to_der)\n    end\n  end\n\n  def test_builtin_curves\n    builtin_curves = OpenSSL::PKey::EC.builtin_curves\n    assert_not_empty builtin_curves\n    assert_equal 2, builtin_curves[0].size\n    assert_kind_of String, builtin_curves[0][0]\n    assert_kind_of String, builtin_curves[0][1]\n\n    builtin_curve_names = builtin_curves.map { |name, comment| name }\n    assert_include builtin_curve_names, \"prime256v1\"\n  end\n\n  def test_generate\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      OpenSSL::PKey::EC.generate(\"non-existent\")\n    }\n    g = OpenSSL::PKey::EC::Group.new(\"prime256v1\")\n    ec = OpenSSL::PKey::EC.generate(g)\n    assert_equal(true, ec.private?)\n    ec = OpenSSL::PKey::EC.generate(\"prime256v1\")\n    assert_equal(true, ec.private?)\n  end\n\n  def test_generate_key\n    ec = OpenSSL::PKey::EC.new(\"prime256v1\")\n    assert_equal false, ec.private?\n    assert_raise(OpenSSL::PKey::PKeyError) { ec.to_der }\n    ec.generate_key!\n    assert_equal true, ec.private?\n    assert_nothing_raised { ec.to_der }\n  end if !openssl?(3, 0, 0)\n\n  def test_marshal\n    key = Fixtures.pkey(\"p256\")\n    deserialized = Marshal.load(Marshal.dump(key))\n\n    assert_equal key.to_der, deserialized.to_der\n  end\n\n  def test_check_key\n    omit_on_fips\n\n    key0 = Fixtures.pkey(\"p256\")\n    assert_equal(true, key0.check_key)\n    assert_equal(true, key0.private?)\n    assert_equal(true, key0.public?)\n\n    key1 = OpenSSL::PKey.read(key0.public_to_der)\n    assert_equal(true, key1.check_key)\n    assert_equal(false, key1.private?)\n    assert_equal(true, key1.public?)\n\n    key2 = OpenSSL::PKey.read(key0.private_to_der)\n    assert_equal(true, key2.private?)\n    assert_equal(true, key2.public?)\n    assert_equal(true, key2.check_key)\n\n    # Behavior of EVP_PKEY_public_check changes between OpenSSL 1.1.1 and 3.0\n    # The public key does not match the private key\n    ec_key_data = <<~EOF\n    -----BEGIN EC PRIVATE KEY-----\n    MHcCAQEEIP+TT0V8Fndsnacji9tyf6hmhHywcOWTee9XkiBeJoVloAoGCCqGSM49\n    AwEHoUQDQgAEBkhhJIU/2/YdPSlY2I1k25xjK4trr5OXSgXvBC21PtY0HQ7lor7A\n    jzT0giJITqmcd81fwGw5+96zLcdxTF1hVQ==\n    -----END EC PRIVATE KEY-----\n    EOF\n    if aws_lc? # AWS-LC automatically does key checks on the parsed key.\n      assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.read(ec_key_data) }\n    else\n      key4 = OpenSSL::PKey.read(ec_key_data)\n      assert_raise(OpenSSL::PKey::PKeyError) { key4.check_key }\n    end\n\n    # EC#private_key= is deprecated in 3.0 and won't work on OpenSSL 3.0\n    if !openssl?(3, 0, 0)\n      key2.private_key += 1\n      assert_raise(OpenSSL::PKey::PKeyError) { key2.check_key }\n    end\n  end\n\n  def test_sign_verify\n    p256 = Fixtures.pkey(\"p256\")\n    data = \"Sign me!\"\n    signature = p256.sign(\"SHA256\", data)\n    assert_equal true, p256.verify(\"SHA256\", signature, data)\n\n    signature0 = (<<~'end;').unpack1(\"m\")\n      MEQCIEOTY/hD7eI8a0qlzxkIt8LLZ8uwiaSfVbjX2dPAvN11AiAQdCYx56Fq\n      QdBp1B4sxJoA8jvODMMklMyBKVmudboA6A==\n    end;\n    assert_equal true, p256.verify(\"SHA256\", signature0, data)\n    signature1 = signature0.succ\n    assert_equal false, p256.verify(\"SHA256\", signature1, data)\n  end\n\n  def test_derive_key\n    # NIST CAVP, KAS_ECC_CDH_PrimitiveTest.txt, P-256 COUNT = 0\n    qCAVSx = \"700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287\"\n    qCAVSy = \"db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac\"\n    dIUT = \"7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534\"\n    zIUT = \"46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b\"\n    a = OpenSSL::PKey::EC.new(\"prime256v1\")\n    a.private_key = OpenSSL::BN.new(dIUT, 16)\n    b = OpenSSL::PKey::EC.new(\"prime256v1\")\n    uncompressed = OpenSSL::BN.new(\"04\" + qCAVSx + qCAVSy, 16)\n    b.public_key = OpenSSL::PKey::EC::Point.new(b.group, uncompressed)\n    assert_equal [zIUT].pack(\"H*\"), a.derive(b)\n\n    assert_equal a.derive(b), a.dh_compute_key(b.public_key)\n  end if !openssl?(3, 0, 0) # TODO: Test it without using #private_key=\n\n  def test_sign_verify_raw\n    key = Fixtures.pkey(\"p256\")\n    data1 = \"foo\"\n    data2 = \"bar\"\n\n    malformed_sig = \"*\" * 30\n\n    # Sign by #dsa_sign_asn1\n    sig = key.dsa_sign_asn1(data1)\n    assert_equal true, key.dsa_verify_asn1(data1, sig)\n    assert_equal false, key.dsa_verify_asn1(data2, sig)\n    assert_sign_verify_false_or_error { key.dsa_verify_asn1(data1, malformed_sig) }\n    assert_equal true, key.verify_raw(nil, sig, data1)\n    assert_equal false, key.verify_raw(nil, sig, data2)\n    assert_sign_verify_false_or_error { key.verify_raw(nil, malformed_sig, data1) }\n\n    # Sign by #sign_raw\n    sig = key.sign_raw(nil, data1)\n    assert_equal true, key.dsa_verify_asn1(data1, sig)\n    assert_equal false, key.dsa_verify_asn1(data2, sig)\n    assert_sign_verify_false_or_error { key.dsa_verify_asn1(data1, malformed_sig) }\n    assert_equal true, key.verify_raw(nil, sig, data1)\n    assert_equal false, key.verify_raw(nil, sig, data2)\n    assert_sign_verify_false_or_error{ key.verify_raw(nil, malformed_sig, data1) }\n  end\n\n  def test_dsa_sign_asn1_FIPS186_3\n    key = OpenSSL::PKey::EC.generate(\"prime256v1\")\n    size = key.group.order.num_bits / 8 + 1\n    dgst = (1..size).to_a.pack('C*')\n    sig = key.dsa_sign_asn1(dgst)\n    # dgst is auto-truncated according to FIPS186-3 after openssl-0.9.8m\n    assert(key.dsa_verify_asn1(dgst + \"garbage\", sig))\n  end\n\n  def test_dh_compute_key\n    key_a = OpenSSL::PKey::EC.generate(\"prime256v1\")\n    key_b = OpenSSL::PKey::EC.generate(key_a.group)\n\n    pub_a = key_a.public_key\n    pub_b = key_b.public_key\n    a = key_a.dh_compute_key(pub_b)\n    b = key_b.dh_compute_key(pub_a)\n    assert_equal a, b\n  end\n\n  def test_ECPrivateKey\n    p256 = Fixtures.pkey(\"p256\")\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Integer(1),\n      OpenSSL::ASN1::OctetString(p256.private_key.to_s(2)),\n      OpenSSL::ASN1::ObjectId(\"prime256v1\", 0, :EXPLICIT),\n      OpenSSL::ASN1::BitString(p256.public_key.to_octet_string(:uncompressed),\n                               1, :EXPLICIT)\n    ])\n    key = OpenSSL::PKey::EC.new(asn1.to_der)\n    assert_predicate key, :private?\n    assert_same_ec p256, key\n\n    pem = <<~EOF\n    -----BEGIN EC PRIVATE KEY-----\n    MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49\n    AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt\n    CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg==\n    -----END EC PRIVATE KEY-----\n    EOF\n    key = OpenSSL::PKey::EC.new(pem)\n    assert_same_ec p256, key\n\n    assert_equal asn1.to_der, p256.to_der\n    assert_equal pem, p256.export\n  end\n\n  def test_ECPrivateKey_with_parameters\n    p256 = Fixtures.pkey(\"p256\")\n\n    # The format used by \"openssl ecparam -name prime256v1 -genkey -outform PEM\"\n    #\n    # \"EC PARAMETERS\" block should be ignored if it is followed by an\n    # \"EC PRIVATE KEY\" block\n    in_pem = <<~EOF\n    -----BEGIN EC PARAMETERS-----\n    BggqhkjOPQMBBw==\n    -----END EC PARAMETERS-----\n    -----BEGIN EC PRIVATE KEY-----\n    MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49\n    AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt\n    CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg==\n    -----END EC PRIVATE KEY-----\n    EOF\n\n    key = OpenSSL::PKey::EC.new(in_pem)\n    assert_same_ec p256, key\n    assert_equal p256.to_der, key.to_der\n  end\n\n  def test_ECPrivateKey_encrypted\n    omit_on_fips\n\n    p256 = Fixtures.pkey(\"p256\")\n    # key = abcdef\n    pem = <<~EOF\n    -----BEGIN EC PRIVATE KEY-----\n    Proc-Type: 4,ENCRYPTED\n    DEK-Info: AES-128-CBC,85743EB6FAC9EA76BF99D9328AFD1A66\n\n    nhsP1NHxb53aeZdzUe9umKKyr+OIwQq67eP0ONM6E1vFTIcjkDcFLR6PhPFufF4m\n    y7E2HF+9uT1KPQhlE+D63i1m1Mvez6PWfNM34iOQp2vEhaoHHKlR3c43lLyzaZDI\n    0/dGSU5SzFG+iT9iFXCwCvv+bxyegkBOyALFje1NAsM=\n    -----END EC PRIVATE KEY-----\n    EOF\n    key = OpenSSL::PKey::EC.new(pem, \"abcdef\")\n    assert_same_ec p256, key\n    key = OpenSSL::PKey::EC.new(pem) { \"abcdef\" }\n    assert_same_ec p256, key\n\n    cipher = OpenSSL::Cipher.new(\"aes-128-cbc\")\n    exported = p256.to_pem(cipher, \"abcdef\\0\\1\")\n    assert_same_ec p256, OpenSSL::PKey::EC.new(exported, \"abcdef\\0\\1\")\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      OpenSSL::PKey::EC.new(exported, \"abcdef\")\n    }\n  end\n\n  def test_PUBKEY\n    p256 = Fixtures.pkey(\"p256\")\n    p256pub = OpenSSL::PKey::EC.new(p256.public_to_der)\n\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Sequence([\n        OpenSSL::ASN1::ObjectId(\"id-ecPublicKey\"),\n        OpenSSL::ASN1::ObjectId(\"prime256v1\")\n      ]),\n      OpenSSL::ASN1::BitString(\n        p256.public_key.to_octet_string(:uncompressed)\n      )\n    ])\n    key = OpenSSL::PKey::EC.new(asn1.to_der)\n    assert_not_predicate key, :private?\n    assert_same_ec p256pub, key\n\n    pem = <<~EOF\n    -----BEGIN PUBLIC KEY-----\n    MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7l\n    SZ/ArK41eGy5wAzU/0G51XttCeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg==\n    -----END PUBLIC KEY-----\n    EOF\n    key = OpenSSL::PKey::EC.new(pem)\n    assert_same_ec p256pub, key\n\n    assert_equal asn1.to_der, key.to_der\n    assert_equal pem, key.export\n\n    assert_equal asn1.to_der, p256.public_to_der\n    assert_equal asn1.to_der, key.public_to_der\n    assert_equal pem, p256.public_to_pem\n    assert_equal pem, key.public_to_pem\n  end\n\n  def test_ec_group\n    group1 = OpenSSL::PKey::EC::Group.new(\"prime256v1\")\n    key1 = OpenSSL::PKey::EC.new(group1)\n    assert_equal group1, key1.group\n\n    group2 = OpenSSL::PKey::EC::Group.new(group1)\n    assert_equal group1.to_der, group2.to_der\n    assert_equal group1, group2\n    group2.asn1_flag ^=OpenSSL::PKey::EC::NAMED_CURVE\n    # AWS-LC does not support serializing explicit curves.\n    unless aws_lc?\n      assert_not_equal group1.to_der, group2.to_der\n    end\n    assert_equal group1, group2\n\n    group3 = group1.dup\n    assert_equal group1.to_der, group3.to_der\n\n    assert group1.asn1_flag & OpenSSL::PKey::EC::NAMED_CURVE # our default\n    der = group1.to_der\n    group4 = OpenSSL::PKey::EC::Group.new(der)\n    group1.point_conversion_form = group4.point_conversion_form = :uncompressed\n    assert_equal :uncompressed, group1.point_conversion_form\n    assert_equal :uncompressed, group4.point_conversion_form\n    assert_equal group1, group4\n    assert_equal group1.curve_name, group4.curve_name\n    assert_equal group1.generator.to_octet_string(:uncompressed),\n      group4.generator.to_octet_string(:uncompressed)\n    assert_equal group1.order, group4.order\n    assert_equal group1.cofactor, group4.cofactor\n    assert_equal group1.seed, group4.seed\n    assert_equal group1.degree, group4.degree\n  end\n\n  def test_ec_group_initialize_error_message\n    # Test that passing 2 arguments raises the helpful error\n    e = assert_raise(ArgumentError) do\n      OpenSSL::PKey::EC::Group.new(:GFp, 123)\n    end\n\n    assert_equal(\"wrong number of arguments (given 2, expected 1 or 4)\", e.message)\n  end\n\n  def test_ec_point\n    group = OpenSSL::PKey::EC::Group.new(\"prime256v1\")\n    key = OpenSSL::PKey::EC.generate(group)\n    point = key.public_key\n\n    point2 = OpenSSL::PKey::EC::Point.new(group, point.to_bn)\n    assert_equal point, point2\n    assert_equal point.to_bn, point2.to_bn\n    assert_equal point.to_octet_string(:uncompressed),\n      point2.to_octet_string(:uncompressed)\n\n    point3 = OpenSSL::PKey::EC::Point.new(group,\n                                          point.to_octet_string(:uncompressed))\n    assert_equal point, point3\n    assert_equal point.to_bn, point3.to_bn\n    assert_equal point.to_octet_string(:uncompressed),\n      point3.to_octet_string(:uncompressed)\n\n    point2.invert!\n    point3.invert!\n    assert_not_equal point.to_octet_string(:uncompressed),\n      point2.to_octet_string(:uncompressed)\n    assert_equal point2.to_octet_string(:uncompressed),\n      point3.to_octet_string(:uncompressed)\n  end\n\n  def test_small_curve\n    begin\n      group = OpenSSL::PKey::EC::Group.new(:GFp, 17, 2, 2)\n      group.point_conversion_form = :uncompressed\n      generator = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 05 01 }))\n      group.set_generator(generator, 19, 1)\n    rescue OpenSSL::PKey::EC::Group::Error\n      pend \"Patched OpenSSL rejected curve\" if /unsupported field/ =~ $!.message\n      raise\n    end\n    assert_equal 17.to_bn.num_bits, group.degree\n    assert_equal B(%w{ 04 05 01 }),\n      group.generator.to_octet_string(:uncompressed)\n    assert_equal 19.to_bn, group.order\n    assert_equal 1.to_bn, group.cofactor\n    assert_nil group.curve_name\n\n    point = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 06 03 }))\n    assert_equal 0x040603.to_bn, point.to_bn\n    assert_equal 0x040603.to_bn, point.to_bn(:uncompressed)\n    assert_equal 0x0306.to_bn, point.to_bn(:compressed)\n    assert_equal 0x070603.to_bn, point.to_bn(:hybrid)\n\n    group2 = group.dup; group2.point_conversion_form = :compressed\n    point2 = OpenSSL::PKey::EC::Point.new(group2, B(%w{ 04 06 03 }))\n    assert_equal 0x0306.to_bn, point2.to_bn\n\n    assert_equal B(%w{ 04 06 03 }), point.to_octet_string(:uncompressed)\n    assert_equal B(%w{ 03 06 }), point.to_octet_string(:compressed)\n    assert_equal B(%w{ 07 06 03 }), point.to_octet_string(:hybrid)\n\n    assert_equal true, point.on_curve?\n    point.invert! # 8.5\n    assert_equal B(%w{ 04 06 0E }), point.to_octet_string(:uncompressed)\n    assert_equal true, point.on_curve?\n\n    assert_equal false, point.infinity?\n    point.set_to_infinity!\n    assert_equal true, point.infinity?\n    assert_equal 0.to_bn, point.to_bn\n    assert_equal B(%w{ 00 }), point.to_octet_string(:uncompressed)\n    assert_equal true, point.on_curve?\n  end\n\n  def test_ec_point_add\n    begin\n      group = OpenSSL::PKey::EC::Group.new(:GFp, 17, 2, 2)\n      group.point_conversion_form = :uncompressed\n      gen = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 05 01 }))\n      group.set_generator(gen, 19, 1)\n\n      point_a = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 06 03 }))\n      point_b = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 10 0D }))\n    rescue OpenSSL::PKey::EC::Group::Error\n      pend \"Patched OpenSSL rejected curve\" if /unsupported field/ =~ $!.message\n      raise\n    end\n\n    result = point_a.add(point_b)\n    assert_equal B(%w{ 04 0D 07 }), result.to_octet_string(:uncompressed)\n\n    assert_raise(TypeError) { point_a.add(nil) }\n    assert_raise(ArgumentError) { point_a.add }\n  end\n\n  def test_ec_point_mul\n    begin\n      # y^2 = x^3 + 2x + 2 over F_17\n      # generator is (5, 1)\n      group = OpenSSL::PKey::EC::Group.new(:GFp, 17, 2, 2)\n      group.point_conversion_form = :uncompressed\n      gen = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 05 01 }))\n      group.set_generator(gen, 19, 1)\n\n      # 3 * (6, 3) = (16, 13)\n      point_a = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 06 03 }))\n      result_a1 = point_a.mul(3)\n      assert_equal B(%w{ 04 10 0D }), result_a1.to_octet_string(:uncompressed)\n      # 3 * (6, 3) + 3 * (5, 1) = (7, 6)\n      result_a2 = point_a.mul(3, 3)\n      assert_equal B(%w{ 04 07 06 }), result_a2.to_octet_string(:uncompressed)\n    rescue OpenSSL::PKey::EC::Group::Error\n      # CentOS patches OpenSSL to reject curves defined over Fp where p < 256 bits\n      raise if $!.message !~ /unsupported field/\n    end\n\n    p256_key = Fixtures.pkey(\"p256\")\n    p256_g = p256_key.group\n    assert_equal(p256_key.public_key, p256_g.generator.mul(p256_key.private_key))\n\n    # invalid argument\n    point = p256_key.public_key\n    assert_raise(TypeError) { point.mul(nil) }\n\n    # mul with arrays was removed in version 4.0.0\n    assert_raise(NotImplementedError) { point.mul([1], []) }\n  end\n\n# test Group: asn1_flag, point_conversion\n\n  private\n\n  def B(ary)\n    [Array(ary).join].pack(\"H*\")\n  end\n\n  def assert_same_ec(expected, key)\n    check_component(expected, key, [:group, :public_key, :private_key])\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_pkey_rsa.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase\n  def test_no_private_exp\n    key = OpenSSL::PKey::RSA.new\n    rsa = Fixtures.pkey(\"rsa-1\")\n    key.set_key(rsa.n, rsa.e, nil)\n    key.set_factors(rsa.p, rsa.q)\n    assert_raise(OpenSSL::PKey::PKeyError){ key.private_encrypt(\"foo\") }\n    assert_raise(OpenSSL::PKey::PKeyError){ key.private_decrypt(\"foo\") }\n  end if !openssl?(3, 0, 0) # Impossible state in OpenSSL 3.0\n\n  def test_private\n    key = Fixtures.pkey(\"rsa-1\")\n\n    # Generated by DER\n    key2 = OpenSSL::PKey::RSA.new(key.to_der)\n    assert_true(key2.private?)\n\n    # public key\n    key3 = key.public_key\n    assert_false(key3.private?)\n\n    # Generated by public key DER\n    key4 = OpenSSL::PKey::RSA.new(key3.to_der)\n    assert_false(key4.private?)\n\n    if !openssl?(3, 0, 0)\n      # Generated by RSA#set_key\n      key5 = OpenSSL::PKey::RSA.new\n      key5.set_key(key.n, key.e, key.d)\n      assert_true(key5.private?)\n\n      # Generated by RSA#set_key, without d\n      key6 = OpenSSL::PKey::RSA.new\n      key6.set_key(key.n, key.e, nil)\n      assert_false(key6.private?)\n    end\n  end\n\n  def test_new\n    key = OpenSSL::PKey::RSA.new(2048)\n    assert_equal 2048, key.n.num_bits\n    assert_equal 65537, key.e\n    assert_not_nil key.d\n    assert(key.private?)\n  end\n\n  def test_new_public_exponent\n    # At least 2024-bits RSA key are required in FIPS.\n    omit_on_fips\n\n    # Specify public exponent\n    key = OpenSSL::PKey::RSA.new(512, 3)\n    assert_equal 512, key.n.num_bits\n    assert_equal 3, key.e\n  end\n\n  def test_new_empty\n    # pkeys are immutable with OpenSSL >= 3.0\n    if openssl?(3, 0, 0)\n      assert_raise(ArgumentError) { OpenSSL::PKey::RSA.new }\n    else\n      key = OpenSSL::PKey::RSA.new\n      assert_nil(key.n)\n    end\n  end\n\n  def test_s_generate\n    key1 = OpenSSL::PKey::RSA.generate(2048)\n    assert_equal 2048, key1.n.num_bits\n    assert_equal 65537, key1.e\n  end\n\n  def test_s_generate_public_exponent\n    # At least 2024-bits RSA key are required in FIPS.\n    omit_on_fips\n\n    # Specify public exponent\n    key = OpenSSL::PKey::RSA.generate(512, 3)\n    assert_equal 512, key.n.num_bits\n    assert_equal 3, key.e\n  end\n\n  def test_new_break\n    assert_nil(OpenSSL::PKey::RSA.new(2048) { break })\n    assert_raise(RuntimeError) do\n      OpenSSL::PKey::RSA.new(2048) { raise }\n    end\n  end\n\n  def test_sign_verify\n    rsa = Fixtures.pkey(\"rsa2048\")\n    data = \"Sign me!\"\n    signature = rsa.sign(\"SHA256\", data)\n    assert_equal true, rsa.verify(\"SHA256\", signature, data)\n\n    signature0 = (<<~'end;').unpack1(\"m\")\n      ooy49i8aeFtkDYUU0RPDsEugGiNw4lZxpbQPnIwtdftEkka945IqKZ/MY3YSw7wKsvBZeaTy8GqL\n      lSWLThsRFDV+UUS9zUBbQ9ygNIT8OjdV+tNL63ZpKGprczSnw4F05MQIpajNRud/8jiI9rf+Wysi\n      WwXecjMl2FlXlLJHY4PFQZU5TiametB4VCQRMcjLo1uf26u/yRpiGaYyqn5vxs0SqNtUDM1UL6x4\n      NHCAdqLjuFRQPjYp1vGLD3eSl4061pS8x1NVap3YGbYfGUyzZO4VfwFwf1jPdhp/OX/uZw4dGB2H\n      gSK+q1JiDFwEE6yym5tdKovL1g1NhFYHF6gkZg==\n    end;\n    assert_equal true, rsa.verify(\"SHA256\", signature0, data)\n    signature1 = signature0.succ\n    assert_equal false, rsa.verify(\"SHA256\", signature1, data)\n  end\n\n  def test_sign_verify_options\n    key = Fixtures.pkey(\"rsa2048\")\n    data = \"Sign me!\"\n    pssopts = {\n      \"rsa_padding_mode\" => \"pss\",\n      \"rsa_pss_saltlen\" => 20,\n      \"rsa_mgf1_md\" => \"SHA256\"\n    }\n    sig_pss = key.sign(\"SHA256\", data, pssopts)\n    assert_equal 256, sig_pss.bytesize\n    assert_equal true, key.verify(\"SHA256\", sig_pss, data, pssopts)\n    assert_equal true, key.verify_pss(\"SHA256\", sig_pss, data,\n                                      salt_length: 20, mgf1_hash: \"SHA256\")\n    # Defaults to PKCS #1 v1.5 padding => verification failure\n    assert_equal false, key.verify(\"SHA256\", sig_pss, data)\n\n    # option type check\n    assert_raise_with_message(TypeError, /expected Hash/) {\n      key.sign(\"SHA256\", data, [\"x\"])\n    }\n  end\n\n  def test_sign_verify_raw\n    key = Fixtures.pkey(\"rsa-1\")\n    data = \"Sign me!\"\n    hash = OpenSSL::Digest.digest(\"SHA256\", data)\n    signature = key.sign_raw(\"SHA256\", hash)\n    assert_equal true, key.verify_raw(\"SHA256\", signature, hash)\n    assert_equal true, key.verify(\"SHA256\", signature, data)\n\n    # Too long data\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      key.sign_raw(\"SHA1\", \"x\" * (key.n.num_bytes + 1))\n    }\n\n    # With options\n    pssopts = {\n      \"rsa_padding_mode\" => \"pss\",\n      \"rsa_pss_saltlen\" => 20,\n      \"rsa_mgf1_md\" => \"SHA256\"\n    }\n    sig_pss = key.sign_raw(\"SHA256\", hash, pssopts)\n    assert_equal true, key.verify(\"SHA256\", sig_pss, data, pssopts)\n    assert_equal true, key.verify_raw(\"SHA256\", sig_pss, hash, pssopts)\n  end\n\n  def test_sign_verify_raw_legacy\n    key = Fixtures.pkey(\"rsa-1\")\n    bits = key.n.num_bits\n\n    # Need right size for raw mode\n    plain0 = \"x\" * (bits/8)\n    cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING)\n    plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING)\n    assert_equal(plain0, plain1)\n\n    # Need smaller size for pkcs1 mode\n    plain0 = \"x\" * (bits/8 - 11)\n    cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING)\n    plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING)\n    assert_equal(plain0, plain1)\n\n    cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default\n    plain1 = key.public_decrypt(cipherdef)\n    assert_equal(plain0, plain1)\n    assert_equal(cipher1, cipherdef)\n\n    # Failure cases\n    assert_raise(ArgumentError){ key.private_encrypt() }\n    assert_raise(ArgumentError){ key.private_encrypt(\"hi\", 1, nil) }\n    assert_raise(OpenSSL::PKey::PKeyError){ key.private_encrypt(plain0, 666) }\n  end\n\n\n  def test_verify_empty_rsa\n    rsa = OpenSSL::PKey::RSA.new\n    assert_raise(OpenSSL::PKey::PKeyError, \"[Bug #12783]\") {\n      rsa.verify(\"SHA1\", \"a\", \"b\")\n    }\n  end unless openssl?(3, 0, 0) # Empty RSA is not possible with OpenSSL >= 3.0\n\n  def test_sign_verify_pss\n    key = Fixtures.pkey(\"rsa2048\")\n    data = \"Sign me!\"\n    invalid_data = \"Sign me?\"\n\n    signature = key.sign_pss(\"SHA256\", data, salt_length: 20, mgf1_hash: \"SHA256\")\n    assert_equal 256, signature.bytesize\n    assert_equal true,\n      key.verify_pss(\"SHA256\", signature, data, salt_length: 20, mgf1_hash: \"SHA256\")\n    assert_equal true,\n      key.verify_pss(\"SHA256\", signature, data, salt_length: :auto, mgf1_hash: \"SHA256\")\n    assert_equal false,\n      key.verify_pss(\"SHA256\", signature, invalid_data, salt_length: 20, mgf1_hash: \"SHA256\")\n\n    signature = key.sign_pss(\"SHA256\", data, salt_length: :digest, mgf1_hash: \"SHA256\")\n    assert_equal true,\n      key.verify_pss(\"SHA256\", signature, data, salt_length: 32, mgf1_hash: \"SHA256\")\n    assert_equal true,\n      key.verify_pss(\"SHA256\", signature, data, salt_length: :auto, mgf1_hash: \"SHA256\")\n    assert_equal false,\n      key.verify_pss(\"SHA256\", signature, data, salt_length: 20, mgf1_hash: \"SHA256\")\n\n    # The sign_pss with `salt_length: :max` raises the \"invalid salt length\"\n    # error in FIPS. We need to skip the tests in FIPS.\n    # According to FIPS 186-5 section 5.4, the salt length shall be between zero\n    # and the output block length of the digest function (inclusive).\n    #\n    # FIPS 186-5 section 5.4 PKCS #1\n    # https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf\n    unless OpenSSL.fips_mode\n      signature = key.sign_pss(\"SHA256\", data, salt_length: :max, mgf1_hash: \"SHA256\")\n      # Should verify on the following salt_length (sLen).\n      # sLen <= emLen (octat) - 2 - hLen (octet) = 2048 / 8 - 2 - 256 / 8 = 222\n      # https://datatracker.ietf.org/doc/html/rfc8017#section-9.1.1\n      assert_equal true,\n        key.verify_pss(\"SHA256\", signature, data, salt_length: 222, mgf1_hash: \"SHA256\")\n      assert_equal true,\n        key.verify_pss(\"SHA256\", signature, data, salt_length: :auto, mgf1_hash: \"SHA256\")\n    end\n\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      key.sign_pss(\"SHA256\", data, salt_length: 223, mgf1_hash: \"SHA256\")\n    }\n  end\n\n  def test_encrypt_decrypt\n    rsapriv = Fixtures.pkey(\"rsa-1\")\n    rsapub = OpenSSL::PKey.read(rsapriv.public_to_der)\n\n    # Defaults to PKCS #1 v1.5\n    raw = \"data\"\n    # According to the NIST SP 800-131A Rev. 2 section 6, PKCS#1 v1.5 padding is\n    # not permitted for key agreement and key transport using RSA in FIPS.\n    # https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf\n    unless OpenSSL.fips_mode\n      enc = rsapub.encrypt(raw)\n      assert_equal raw, rsapriv.decrypt(enc)\n    end\n\n    # Invalid options\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      rsapub.encrypt(raw, { \"nonexistent\" => \"option\" })\n    }\n  end\n\n  def test_encrypt_decrypt_legacy\n    rsapriv = Fixtures.pkey(\"rsa-1\")\n    rsapub = OpenSSL::PKey.read(rsapriv.public_to_der)\n\n    # Defaults to PKCS #1 v1.5\n    unless OpenSSL.fips_mode\n      raw = \"data\"\n      enc_legacy = rsapub.public_encrypt(raw)\n      assert_equal raw, rsapriv.decrypt(enc_legacy)\n      enc_new = rsapub.encrypt(raw)\n      assert_equal raw, rsapriv.private_decrypt(enc_new)\n    end\n\n    # OAEP with default parameters\n    raw = \"data\"\n    enc_legacy = rsapub.public_encrypt(raw, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)\n    assert_equal raw, rsapriv.decrypt(enc_legacy, { \"rsa_padding_mode\" => \"oaep\" })\n    enc_new = rsapub.encrypt(raw, { \"rsa_padding_mode\" => \"oaep\" })\n    assert_equal raw, rsapriv.private_decrypt(enc_legacy, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)\n  end\n\n  def test_export\n    orig = Fixtures.pkey(\"rsa-1\")\n\n    pub = OpenSSL::PKey.read(orig.public_to_der)\n    assert_not_equal orig.export, pub.export\n    assert_equal orig.public_to_pem, pub.export\n\n    # PKey is immutable in OpenSSL >= 3.0\n    if !openssl?(3, 0, 0)\n      key = OpenSSL::PKey::RSA.new\n\n      # key has only n, e and d\n      key.set_key(orig.n, orig.e, orig.d)\n      assert_equal orig.public_key.export, key.export\n\n      # key has only n, e, d, p and q\n      key.set_factors(orig.p, orig.q)\n      assert_equal orig.public_key.export, key.export\n\n      # key has n, e, d, p, q, dmp1, dmq1 and iqmp\n      key.set_crt_params(orig.dmp1, orig.dmq1, orig.iqmp)\n      assert_equal orig.export, key.export\n    end\n  end\n\n  def test_to_der\n    orig = Fixtures.pkey(\"rsa-1\")\n\n    pub = OpenSSL::PKey.read(orig.public_to_der)\n    assert_not_equal orig.to_der, pub.to_der\n    assert_equal orig.public_to_der, pub.to_der\n\n    # PKey is immutable in OpenSSL >= 3.0\n    if !openssl?(3, 0, 0)\n      key = OpenSSL::PKey::RSA.new\n\n      # key has only n, e and d\n      key.set_key(orig.n, orig.e, orig.d)\n      assert_equal orig.public_key.to_der, key.to_der\n\n      # key has only n, e, d, p and q\n      key.set_factors(orig.p, orig.q)\n      assert_equal orig.public_key.to_der, key.to_der\n\n      # key has n, e, d, p, q, dmp1, dmq1 and iqmp\n      key.set_crt_params(orig.dmp1, orig.dmq1, orig.iqmp)\n      assert_equal orig.to_der, key.to_der\n    end\n  end\n\n  def test_RSAPrivateKey\n    rsa = Fixtures.pkey(\"rsa-1\")\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Integer(0),\n      OpenSSL::ASN1::Integer(rsa.n),\n      OpenSSL::ASN1::Integer(rsa.e),\n      OpenSSL::ASN1::Integer(rsa.d),\n      OpenSSL::ASN1::Integer(rsa.p),\n      OpenSSL::ASN1::Integer(rsa.q),\n      OpenSSL::ASN1::Integer(rsa.dmp1),\n      OpenSSL::ASN1::Integer(rsa.dmq1),\n      OpenSSL::ASN1::Integer(rsa.iqmp)\n    ])\n    key = OpenSSL::PKey::RSA.new(asn1.to_der)\n    assert_predicate key, :private?\n    assert_same_rsa rsa, key\n\n    pem = der_to_pem(asn1.to_der, \"RSA PRIVATE KEY\")\n    key = OpenSSL::PKey::RSA.new(pem)\n    assert_same_rsa rsa, key\n\n    assert_equal asn1.to_der, rsa.to_der\n    assert_equal pem, rsa.export\n\n    # Unknown PEM prepended\n    cert = issue_cert(OpenSSL::X509::Name.new([[\"CN\", \"nobody\"]]), rsa, 1, [], nil, nil)\n    str = cert.to_text + cert.to_pem + rsa.to_pem\n    key = OpenSSL::PKey::RSA.new(str)\n    assert_same_rsa rsa, key\n  end\n\n  def test_RSAPrivateKey_encrypted\n    # PKCS #1 RSAPrivateKey with OpenSSL encryption\n    omit_on_fips\n\n    rsa = Fixtures.pkey(\"rsa2048\")\n\n    pem = der_to_encrypted_pem(rsa.to_der, \"RSA PRIVATE KEY\", \"abcdef\")\n    key = OpenSSL::PKey::RSA.new(pem, \"abcdef\")\n    assert_same_rsa rsa, key\n    key = OpenSSL::PKey::RSA.new(pem) { \"abcdef\" }\n    assert_same_rsa rsa, key\n\n    cipher = OpenSSL::Cipher.new(\"aes-128-cbc\")\n    exported = rsa.to_pem(cipher, \"abcdef\\0\\1\")\n    assert_same_rsa rsa, OpenSSL::PKey::RSA.new(exported, \"abcdef\\0\\1\")\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      OpenSSL::PKey::RSA.new(exported, \"abcdef\")\n    }\n  end\n\n  def test_RSAPublicKey\n    # PKCS #1 RSAPublicKey. Only decoding is supported\n    orig = Fixtures.pkey(\"rsa-1\")\n    pub = OpenSSL::PKey::RSA.new(orig.public_to_der)\n\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Integer(orig.n),\n      OpenSSL::ASN1::Integer(orig.e)\n    ])\n    key = OpenSSL::PKey::RSA.new(asn1.to_der)\n    assert_not_predicate key, :private?\n    assert_same_rsa pub, key\n\n    pem = der_to_pem(asn1.to_der, \"RSA PUBLIC KEY\")\n    key = OpenSSL::PKey::RSA.new(pem)\n    assert_same_rsa pub, key\n  end\n\n  def test_PUBKEY\n    orig = Fixtures.pkey(\"rsa-1\")\n    pub = OpenSSL::PKey::RSA.new(orig.public_to_der)\n\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Sequence([\n        OpenSSL::ASN1::ObjectId(\"rsaEncryption\"),\n        OpenSSL::ASN1::Null(nil)\n      ]),\n      OpenSSL::ASN1::BitString(\n        OpenSSL::ASN1::Sequence([\n          OpenSSL::ASN1::Integer(orig.n),\n          OpenSSL::ASN1::Integer(orig.e)\n        ]).to_der\n      )\n    ])\n    key = OpenSSL::PKey::RSA.new(asn1.to_der)\n    assert_not_predicate key, :private?\n    assert_same_rsa pub, key\n\n    pem = der_to_pem(asn1.to_der, \"PUBLIC KEY\")\n    key = OpenSSL::PKey::RSA.new(pem)\n    assert_same_rsa pub, key\n\n    assert_equal asn1.to_der, key.to_der\n    assert_equal pem, key.export\n\n    assert_equal asn1.to_der, orig.public_to_der\n    assert_equal asn1.to_der, key.public_to_der\n    assert_equal pem, orig.public_to_pem\n    assert_equal pem, key.public_to_pem\n  end\n\n  def test_pem_passwd\n    omit_on_fips\n\n    key = Fixtures.pkey(\"rsa-1\")\n    pem3c = key.to_pem(\"aes-128-cbc\", \"key\")\n    assert_match (/ENCRYPTED/), pem3c\n    assert_equal key.to_der, OpenSSL::PKey.read(pem3c, \"key\").to_der\n    assert_equal key.to_der, OpenSSL::PKey.read(pem3c) { \"key\" }.to_der\n    assert_raise(OpenSSL::PKey::PKeyError) {\n      OpenSSL::PKey.read(pem3c) { nil }\n    }\n  end\n\n  def test_private_encoding\n    pkey = Fixtures.pkey(\"rsa-1\")\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Integer(0),\n      OpenSSL::ASN1::Sequence([\n        OpenSSL::ASN1::ObjectId(\"rsaEncryption\"),\n        OpenSSL::ASN1::Null(nil)\n      ]),\n      OpenSSL::ASN1::OctetString(pkey.to_der)\n    ])\n    assert_equal asn1.to_der, pkey.private_to_der\n    assert_same_rsa pkey, OpenSSL::PKey.read(asn1.to_der)\n\n    pem = der_to_pem(asn1.to_der, \"PRIVATE KEY\")\n    assert_equal pem, pkey.private_to_pem\n    assert_same_rsa pkey, OpenSSL::PKey.read(pem)\n  end\n\n  def test_private_encoding_encrypted\n    rsa = Fixtures.pkey(\"rsa2048\")\n    encoded = rsa.private_to_der(\"aes-128-cbc\", \"abcdefgh\")\n    asn1 = OpenSSL::ASN1.decode(encoded) # PKCS #8 EncryptedPrivateKeyInfo\n    assert_kind_of OpenSSL::ASN1::Sequence, asn1\n    assert_equal 2, asn1.value.size\n    assert_not_equal rsa.private_to_der, encoded\n    assert_same_rsa rsa, OpenSSL::PKey.read(encoded, \"abcdefgh\")\n    assert_same_rsa rsa, OpenSSL::PKey.read(encoded) { \"abcdefgh\" }\n    assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.read(encoded, \"abcxyz\") }\n\n    encoded = rsa.private_to_pem(\"aes-128-cbc\", \"abcdefgh\")\n    assert_match (/BEGIN ENCRYPTED PRIVATE KEY/), encoded.lines[0]\n    assert_same_rsa rsa, OpenSSL::PKey.read(encoded, \"abcdefgh\")\n\n    # Use openssl instead of certtool due to https://gitlab.com/gnutls/gnutls/-/issues/1632\n    # openssl pkcs8 -in test/openssl/fixtures/pkey/rsa2048.pem -topk8 -v2 aes-128-cbc -passout pass:abcdefgh\n    pem = <<~EOF\n-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQ+Sg92Hgy8EgVPf7t\nHen1qwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEB5UX2xdDO8/AKA8\n+Y5CZyUEggTQkArh4mMPpnAe3xOcDKMz8KCn5lrLb/6Dla7Rp9LHKGkUfyI11EZt\nm+OIriwy9oDQquKyVuLQVGAxXKk+3pyxMqLB0i3hLYamT3vzoPctyVwjuRuKoU3E\nCbF0YhCoxvWMvjHsolwYzx00DbLXouE4BGKvPjnhw5hwtdoZ9Px0ZnCXCxVXi8z/\nmlw7a2ptKEiHQVjuPPbttq+dA+ez7pbWonWVod5TMaPtyEZu5XfPD+0pMboceHZg\nH8ehgUhV3mzEJiisFGg1q9hj+4BaFl5m4tvqp43inCCdShE78CNnOPzJ7WCjKJqi\njGvHjeMoVx3rZXHcZDAzfIZvDigp9uAfzjRJjpRG8sg5sDQVC7vdUhQDe5TorKT2\nVb0tdVYxoEpMJ3dhU6Ds5JxMR6GTLjsjTqOkAl6db3HxulwfEpr7YjOpfODR+ttA\nBeIcUcMLsDHayIaQaMLIftHxOkfX7UxoFW9CMG5UMQf/m3eEgVUwgK/E5sUJRUTo\nyhRzJ4NAP4fgc4YH9tbzvUrhfdCXCBEOn6IlDQL66SZr8Mm+Ggu4Ij4TnKWXLrXL\nnSTDDa42kPOvtedKqxC/uXE7rrfh+uyw6J6OjSl6u86TIebndLuDo5DTdWKh8rsg\nfvZZ6332dfMp8JC9/4YnYIJdI7acInSoyHp52OB+2+dgYCr5OrZFjjKS7nELVfo7\nOxGy6uH3NHF9qyUEf3MN17TRHI7jP3zKbXcDTPSyxLQkWe/CU5B251CTmoTSidSW\nEhKnPlGZYbpVQJ4KGEL5UeY8W9PXQo4Dl7TmXBGvuPqNF8kMB3XrPIph7GmihmX0\nnlJqLk9eiRFmUETS0IdAyKJrm4R9Hf6rjYCbXlaApylyVUdSZ2BxgeoTY9BA6Kgf\n3xlgMv01MoUkXMx2+OLIc9MzhButQiDxh3mfS012CjKqUFrJhRSa8DOpUfVgmXpq\n/HP4drWamLWYJR8FsmJS11ZYc1EK/ctJTSpqfewvoUGOSHomhh7zXn1Acb6+9/3p\nbcrJjoR5K8Jg6NlG4dSNkpY/x92I7bFLXFqELIH5tteDrlQen5eASjaiyPPAoOw8\nIGfOmFS4VUPh1VP6g8Jtn5Hr2qXB3DoQoI6EvUZhJ6GJfi67mx5VKux6G9MzJkix\nGU1cL4WzWK2DU0l39UxXjS+4TmOYbrqLVnVMjusX0fwb8LkDC/fVohbhLwhHNwu6\nnSTSEpS9zSDrv1JXFtAtPv6XCSFs6ssPWJMwGSdThn7EfV0GEhG2mCzTyVhwxxQo\n6U/Suqq4oMZoracPUCZx0E4u/bb4KBoFA/eBNPJENTR18IiV+D7wAxlxauO3N1t4\niJxwrrvSgQPmOGuxrh5LVD41UXYUWLtndzabnpByppFn2MbmvrqJgon0MSs84cTA\n7scnbPu1V3PpKy/t67gtVw9Ue8hLjrskWB1JPFYr7vRWvJzYjfbflyroF+QEJ3TA\n6rTfUC9+ePci6T+i9jF4xcmzqYzRtnGtp5nRUitJGw0uwBTDwzfI2WD6ltvvu7lc\npHuzvY5zEapuu1JhjHLUd+OE8rVVM999DUXo/IDLsWyRCphCiYfVXJNogd9rB0Ta\n5AhVgpRhxkarBURZyLTYj7NRxCsbHq7XExJNrIdRG/KlBQfyEyIzZ7E=\n-----END ENCRYPTED PRIVATE KEY-----\n    EOF\n    assert_same_rsa rsa, OpenSSL::PKey.read(pem, \"abcdefgh\")\n  end\n\n  def test_params\n    key = Fixtures.pkey(\"rsa2048\")\n    assert_equal(2048, key.n.num_bits)\n    assert_equal(key.n, key.params[\"n\"])\n    assert_equal(65537, key.e)\n    assert_equal(key.e, key.params[\"e\"])\n    [:d, :p, :q, :dmp1, :dmq1, :iqmp].each do |name|\n      assert_kind_of(OpenSSL::BN, key.send(name))\n      assert_equal(key.send(name), key.params[name.to_s])\n    end\n\n    pubkey = OpenSSL::PKey.read(key.public_to_der)\n    assert_equal(key.n, pubkey.n)\n    assert_equal(key.e, pubkey.e)\n    [:d, :p, :q, :dmp1, :dmq1, :iqmp].each do |name|\n      assert_nil(pubkey.send(name))\n      assert_nil(pubkey.params[name.to_s])\n    end\n  end\n\n  def test_dup\n    key = Fixtures.pkey(\"rsa-1\")\n    key2 = key.dup\n    assert_equal key.params, key2.params\n\n    # PKey is immutable in OpenSSL >= 3.0\n    if !openssl?(3, 0, 0)\n      key2.set_key(key2.n, 3, key2.d)\n      assert_not_equal key.params, key2.params\n    end\n  end\n\n  def test_marshal\n    key = Fixtures.pkey(\"rsa-1\")\n    deserialized = Marshal.load(Marshal.dump(key))\n\n    assert_equal key.to_der, deserialized.to_der\n  end\n\n  private\n  def assert_same_rsa(expected, key)\n    check_component(expected, key, [:n, :e, :d, :p, :q, :dmp1, :dmq1, :iqmp])\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_provider.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\nif defined?(OpenSSL) && defined?(OpenSSL::Provider)\n\nclass OpenSSL::TestProvider < OpenSSL::TestCase\n  def test_openssl_provider_name_inspect\n    with_openssl <<-'end;'\n      provider = OpenSSL::Provider.load(\"default\")\n      assert_equal(\"default\", provider.name)\n      assert_not_nil(provider.inspect)\n    end;\n  end\n\n  def test_openssl_provider_names\n    # We expect the following providers are loaded in the cases:\n    # * Non-FIPS: default\n    # * FIPS: fips, base\n    # Use the null provider to test the added provider.\n    # See provider(7) - OPENSSL PROVIDERS to see the list of providers, and\n    # OSSL_PROVIDER-null(7) to check the details of the null provider.\n    with_openssl <<-'end;'\n      num = OpenSSL::Provider.provider_names.size\n\n      added_provider = OpenSSL::Provider.load(\"null\")\n      assert_equal(num + 1, OpenSSL::Provider.provider_names.size)\n      assert_includes(OpenSSL::Provider.provider_names, \"null\")\n\n      assert_equal(true, added_provider.unload)\n      assert_equal(num, OpenSSL::Provider.provider_names.size)\n      assert_not_includes(OpenSSL::Provider.provider_names, \"null\")\n    end;\n  end\n\n  def test_unloaded_openssl_provider\n    with_openssl <<-'end;'\n      default_provider = OpenSSL::Provider.load(\"default\")\n      assert_equal(true, default_provider.unload)\n      assert_raise(OpenSSL::Provider::ProviderError) { default_provider.name }\n      assert_raise(OpenSSL::Provider::ProviderError) { default_provider.unload }\n    end;\n  end\n\n  def test_openssl_legacy_provider\n    # The legacy provider is not supported on FIPS.\n    omit_on_fips\n\n    with_openssl(<<-'end;')\n      begin\n        OpenSSL::Provider.load(\"default\")\n        OpenSSL::Provider.load(\"legacy\")\n      rescue OpenSSL::Provider::ProviderError\n        omit \"Only for OpenSSL with legacy provider\"\n      end\n\n      algo = \"RC4\"\n      data = \"a\" * 1000\n      key = OpenSSL::Random.random_bytes(16)\n\n      # default provider does not support RC4\n      cipher = OpenSSL::Cipher.new(algo)\n      cipher.encrypt\n      cipher.key = key\n      encrypted = cipher.update(data) + cipher.final\n\n      other_cipher = OpenSSL::Cipher.new(algo)\n      other_cipher.decrypt\n      other_cipher.key = key\n      decrypted = other_cipher.update(encrypted) + other_cipher.final\n\n      assert_equal(data, decrypted)\n    end;\n  end\n\n  private\n\n  # this is required because OpenSSL::Provider methods change global state\n  def with_openssl(code, **opts)\n    assert_separately([\"-ropenssl\"], <<~\"end;\", **opts)\n      #{code}\n    end;\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_random.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestRandom < OpenSSL::TestCase\n  def test_random_bytes\n    assert_equal(\"\", OpenSSL::Random.random_bytes(0))\n    assert_equal(12, OpenSSL::Random.random_bytes(12).bytesize)\n  end\n\n  def test_pseudo_bytes\n    # deprecated as of OpenSSL 1.1.0\n    assert_equal(\"\", OpenSSL::Random.pseudo_bytes(0))\n    assert_equal(12, OpenSSL::Random.pseudo_bytes(12).bytesize)\n  end if OpenSSL::Random.methods.include?(:pseudo_bytes)\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_ssl.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL::SSL)\n\nclass OpenSSL::TestSSL < OpenSSL::SSLTestCase\n  def test_bad_socket\n    bad_socket = Struct.new(:sync).new\n    assert_raise TypeError do\n      socket = OpenSSL::SSL::SSLSocket.new bad_socket\n      # if the socket is not a T_FILE, `connect` will segv because it tries\n      # to get the underlying file descriptor but the API it calls assumes\n      # the object type is T_FILE\n      socket.connect\n    end\n  end\n\n  def test_ctx_setup\n    ctx = OpenSSL::SSL::SSLContext.new\n    assert_equal true, ctx.setup\n    assert_predicate ctx, :frozen?\n    assert_equal nil, ctx.setup\n  end\n\n  def test_ctx_options\n    ctx = OpenSSL::SSL::SSLContext.new\n\n    ctx.options = 4\n    assert_equal 4, ctx.options & 4\n    if ctx.options != 4\n      pend \"SSL_CTX_set_options() seems to be modified by distributor\"\n    end\n    ctx.options = nil\n    assert_equal OpenSSL::SSL::OP_ALL, ctx.options\n\n    assert_equal true, ctx.setup\n    assert_predicate ctx, :frozen?\n    assert_equal nil, ctx.setup\n  end\n\n  def test_ctx_options_config\n    omit \"LibreSSL and AWS-LC do not support OPENSSL_CONF\" if libressl? || aws_lc?\n\n    Tempfile.create(\"openssl.cnf\") { |f|\n      f.puts(<<~EOF)\n        openssl_conf = default_conf\n        [default_conf]\n        ssl_conf = ssl_sect\n        [ssl_sect]\n        system_default = ssl_default_sect\n        [ssl_default_sect]\n        Options = -SessionTicket\n      EOF\n      f.close\n\n      assert_separately([{ \"OPENSSL_CONF\" => f.path }, \"-ropenssl\"], <<~\"end;\")\n        ctx = OpenSSL::SSL::SSLContext.new\n        assert_equal OpenSSL::SSL::OP_NO_TICKET, ctx.options & OpenSSL::SSL::OP_NO_TICKET\n        ctx.set_params\n        assert_equal OpenSSL::SSL::OP_NO_TICKET, ctx.options & OpenSSL::SSL::OP_NO_TICKET\n      end;\n    }\n  end\n\n  def test_ssl_with_server_cert\n    ctx_proc = -> ctx {\n      ctx.cert = @svr_cert\n      ctx.key = @svr_key\n      ctx.extra_chain_cert = [@ca_cert]\n    }\n    server_proc = -> (ctx, ssl) {\n      assert_equal @svr_cert.to_der, ssl.cert.to_der\n      assert_equal nil, ssl.peer_cert\n\n      readwrite_loop(ctx, ssl)\n    }\n    start_server(ctx_proc: ctx_proc, server_proc: server_proc) { |port|\n      begin\n        sock = TCPSocket.new(\"127.0.0.1\", port)\n        ctx = OpenSSL::SSL::SSLContext.new\n        ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n        ssl.connect\n\n        assert_equal sock, ssl.io\n        assert_equal nil, ssl.cert\n        assert_equal @svr_cert.to_der, ssl.peer_cert.to_der\n        assert_equal 2, ssl.peer_cert_chain.size\n        assert_equal @svr_cert.to_der, ssl.peer_cert_chain[0].to_der\n        assert_equal @ca_cert.to_der, ssl.peer_cert_chain[1].to_der\n\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      ensure\n        ssl&.close\n        sock&.close\n      end\n    }\n  end\n\n  def test_socket_open\n    start_server { |port|\n      begin\n        ssl = OpenSSL::SSL::SSLSocket.open(\"127.0.0.1\", port)\n        ssl.sync_close = true\n        ssl.connect\n\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      ensure\n        ssl&.close\n      end\n    }\n  end\n\n  def test_socket_open_with_context\n    start_server { |port|\n      begin\n        ctx = OpenSSL::SSL::SSLContext.new\n        ssl = OpenSSL::SSL::SSLSocket.open(\"127.0.0.1\", port, context: ctx)\n        ssl.sync_close = true\n        ssl.connect\n\n        assert_equal ssl.context, ctx\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      ensure\n        ssl&.close\n      end\n    }\n  end\n\n  def test_socket_open_with_local_address_port_context\n    start_server { |port|\n      begin\n        # Guess a free port number\n        random_port = rand(49152..65535)\n        ctx = OpenSSL::SSL::SSLContext.new\n        ssl = OpenSSL::SSL::SSLSocket.open(\"127.0.0.1\", port, \"127.0.0.1\", random_port, context: ctx)\n        ssl.sync_close = true\n        ssl.connect\n\n        assert_equal ctx, ssl.context\n        assert_equal random_port, ssl.io.local_address.ip_port\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      rescue Errno::EADDRINUSE, Errno::EACCES\n      ensure\n        ssl&.close\n      end\n    }\n  end\n\n  def test_socket_close_write\n    server_proc = proc do |ctx, ssl|\n      message = ssl.read\n      ssl.write(message)\n      ssl.close_write\n    ensure\n      ssl.close\n    end\n\n    start_server(server_proc: server_proc) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ssl = OpenSSL::SSL::SSLSocket.open(\"127.0.0.1\", port, context: ctx)\n      ssl.sync_close = true\n      ssl.connect\n\n      message = \"abc\"*1024\n      ssl.write message\n      ssl.close_write\n      assert_equal message, ssl.read\n    ensure\n      ssl&.close\n    end\n  end\n\n  def test_add_certificate\n    ctx_proc = -> ctx {\n      # Unset values set by start_server\n      ctx.cert = ctx.key = ctx.extra_chain_cert = nil\n      ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      server_connect(port) { |ssl|\n        assert_equal @svr_cert.subject, ssl.peer_cert.subject\n        assert_equal [@svr_cert.subject, @ca_cert.subject],\n          ssl.peer_cert_chain.map(&:subject)\n\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n    end\n  end\n\n  def test_add_certificate_multiple_certs\n    ca2_key = Fixtures.pkey(\"rsa-3\")\n    ca2_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign, keyCertSign\", true],\n    ]\n    ca2_dn = OpenSSL::X509::Name.parse_rfc2253(\"CN=CA2\")\n    ca2_cert = issue_cert(ca2_dn, ca2_key, 123, ca2_exts, nil, nil)\n\n    ecdsa_key = Fixtures.pkey(\"p256\")\n    exts = [\n      [\"keyUsage\", \"digitalSignature\", false],\n    ]\n    ecdsa_dn = OpenSSL::X509::Name.parse_rfc2253(\"CN=localhost2\")\n    ecdsa_cert = issue_cert(ecdsa_dn, ecdsa_key, 456, exts, ca2_cert, ca2_key)\n\n    ctx_proc = -> ctx {\n      # Unset values set by start_server\n      ctx.cert = ctx.key = ctx.extra_chain_cert = nil\n      ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA\n      ctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert])\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.max_version = :TLS1_2 # TODO: We need this to force certificate type\n      ctx.ciphers = \"aECDSA\"\n      server_connect(port, ctx) { |ssl|\n        assert_equal ecdsa_cert.subject, ssl.peer_cert.subject\n        assert_equal [ecdsa_cert.subject, ca2_cert.subject],\n          ssl.peer_cert_chain.map(&:subject)\n      }\n\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.max_version = :TLS1_2\n      ctx.ciphers = \"aRSA\"\n      server_connect(port, ctx) { |ssl|\n        assert_equal @svr_cert.subject, ssl.peer_cert.subject\n        assert_equal [@svr_cert.subject, @ca_cert.subject],\n          ssl.peer_cert_chain.map(&:subject)\n      }\n    end\n  end\n\n  def test_extra_chain_cert_auto_chain\n    start_server { |port|\n      server_connect(port) { |ssl|\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        assert_equal @svr_cert.to_der, ssl.peer_cert.to_der\n        assert_equal [@svr_cert], ssl.peer_cert_chain\n      }\n    }\n\n    # AWS-LC enables SSL_MODE_NO_AUTO_CHAIN by default\n    unless aws_lc?\n      ctx_proc = -> ctx {\n        # Sanity check: start_server won't set extra_chain_cert\n        assert_nil ctx.extra_chain_cert\n        ctx.cert_store = OpenSSL::X509::Store.new.tap { |store|\n          store.add_cert(@ca_cert)\n        }\n      }\n      start_server(ctx_proc: ctx_proc) { |port|\n        server_connect(port) { |ssl|\n          ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n          assert_equal @svr_cert.to_der, ssl.peer_cert.to_der\n          assert_equal [@svr_cert, @ca_cert], ssl.peer_cert_chain\n        }\n      }\n    end\n  end\n\n  def test_sysread_and_syswrite\n    start_server { |port|\n      server_connect(port) { |ssl|\n        str = +(\"x\" * 100 + \"\\n\")\n        ssl.syswrite(str)\n        newstr = ssl.sysread(str.bytesize)\n        assert_equal(str, newstr)\n\n        buf = String.new\n        ssl.syswrite(str)\n        assert_same buf, ssl.sysread(str.size, buf)\n        assert_equal(str, buf)\n\n        obj = Object.new\n        obj.define_singleton_method(:to_str) { str }\n        ssl.syswrite(obj)\n        assert_equal(str, ssl.sysread(str.bytesize))\n      }\n    }\n  end\n\n  def test_read_with_timeout\n    omit \"does not support timeout\" unless IO.method_defined?(:timeout)\n\n    start_server do |port|\n      server_connect(port) do |ssl|\n        str = +(\"x\" * 100 + \"\\n\")\n        ssl.syswrite(str)\n        assert_equal(str, ssl.sysread(str.bytesize))\n\n        ssl.timeout = 0.1\n        assert_raise(IO::TimeoutError) { ssl.sysread(1) }\n\n        ssl.syswrite(str)\n        assert_equal(str, ssl.sysread(str.bytesize))\n\n        buf = \"orig\".b\n        assert_raise(IO::TimeoutError) { ssl.sysread(1, buf) }\n        assert_equal(\"orig\", buf)\n        assert_nothing_raised { buf.clear }\n      end\n    end\n  end\n\n  def test_getbyte\n    start_server { |port|\n      server_connect(port) { |ssl|\n        str = +(\"x\" * 100 + \"\\n\")\n        ssl.syswrite(str)\n        newstr = str.bytesize.times.map { |i|\n          ssl.getbyte\n        }.pack(\"C*\")\n        assert_equal(str, newstr)\n      }\n    }\n  end\n\n  def test_readbyte\n    start_server { |port|\n      server_connect(port) { |ssl|\n        str = +(\"x\" * 100 + \"\\n\")\n        ssl.syswrite(str)\n        newstr = str.bytesize.times.map { |i|\n          ssl.readbyte\n        }.pack(\"C*\")\n        assert_equal(str, newstr)\n      }\n    }\n  end\n\n  def test_sync_close\n    start_server do |port|\n      begin\n        sock = TCPSocket.new(\"127.0.0.1\", port)\n        ssl = OpenSSL::SSL::SSLSocket.new(sock)\n        ssl.connect\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        ssl.close\n        assert_not_predicate sock, :closed?\n      ensure\n        sock&.close\n      end\n\n      begin\n        sock = TCPSocket.new(\"127.0.0.1\", port)\n        ssl = OpenSSL::SSL::SSLSocket.new(sock)\n        ssl.sync_close = true  # !!\n        ssl.connect\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        ssl.close\n        assert_predicate sock, :closed?\n      ensure\n        sock&.close\n      end\n    end\n  end\n\n  def test_sync_close_initialize_opt\n    start_server do |port|\n      begin\n        sock = TCPSocket.new(\"127.0.0.1\", port)\n        ssl = OpenSSL::SSL::SSLSocket.new(sock, sync_close: true)\n        assert_equal true, ssl.sync_close\n        ssl.connect\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        ssl.close\n        assert_predicate sock, :closed?\n      ensure\n        sock&.close\n      end\n    end\n  end\n\n  def test_copy_stream\n    start_server do |port|\n      server_connect(port) do |ssl|\n        IO.pipe do |r, w|\n          str = \"hello world\\n\"\n          w.write(str)\n          IO.copy_stream(r, ssl, str.bytesize)\n          IO.copy_stream(ssl, w, str.bytesize)\n          assert_equal str, r.read(str.bytesize)\n        end\n      end\n    end\n  end\n\n  def test_verify_mode_default\n    ctx = OpenSSL::SSL::SSLContext.new\n    assert_equal OpenSSL::SSL::VERIFY_NONE, ctx.verify_mode\n  end\n\n  def test_verify_mode_server_cert\n    start_server(ignore_listener_error: true) { |port|\n      populated_store = OpenSSL::X509::Store.new\n      populated_store.add_cert(@ca_cert)\n      empty_store = OpenSSL::X509::Store.new\n\n      # Valid certificate, SSL_VERIFY_PEER\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n      ctx.cert_store = populated_store\n      assert_nothing_raised {\n        server_connect(port, ctx) { |ssl| ssl.puts(\"abc\"); ssl.gets }\n      }\n\n      # Invalid certificate, SSL_VERIFY_NONE\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE\n      ctx.cert_store = empty_store\n      assert_nothing_raised {\n        server_connect(port, ctx) { |ssl| ssl.puts(\"abc\"); ssl.gets }\n      }\n\n      # Invalid certificate, SSL_VERIFY_PEER\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n      ctx.cert_store = empty_store\n      assert_raise(OpenSSL::SSL::SSLError) {\n        server_connect(port, ctx)\n      }\n    }\n  end\n\n  def test_verify_mode_client_cert_required\n    # Optional, client certificate not supplied\n    vflag = OpenSSL::SSL::VERIFY_PEER\n    accept_proc = -> ssl {\n      assert_equal nil, ssl.peer_cert\n    }\n    start_server(verify_mode: vflag, accept_proc: accept_proc) { |port|\n      assert_nothing_raised {\n        server_connect(port) { |ssl| ssl.puts(\"abc\"); ssl.gets }\n      }\n    }\n\n    # Required, client certificate not supplied\n    vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT\n    start_server(verify_mode: vflag, ignore_listener_error: true) { |port|\n      assert_handshake_error {\n        server_connect(port) { |ssl| ssl.puts(\"abc\"); ssl.gets }\n      }\n    }\n  end\n\n  def test_client_auth_success\n    vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT\n    ctx_proc = proc { |ctx|\n      store = OpenSSL::X509::Store.new\n      store.add_cert(@ca_cert)\n      store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT\n      ctx.cert_store = store\n      # LibreSSL doesn't support client_cert_cb in TLS 1.3\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?\n    }\n    start_server(verify_mode: vflag, ctx_proc: ctx_proc) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.key = @cli_key\n      ctx.cert = @cli_cert\n\n      server_connect(port, ctx) { |ssl|\n        ssl.puts(\"foo\")\n        assert_equal(\"foo\\n\", ssl.gets)\n      }\n\n      called = nil\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.client_cert_cb = Proc.new{ |sslconn|\n        called = true\n        [@cli_cert, @cli_key]\n      }\n\n      server_connect(port, ctx) { |ssl|\n        assert(called)\n        ssl.puts(\"foo\")\n        assert_equal(\"foo\\n\", ssl.gets)\n      }\n    }\n  end\n\n  def test_client_cert_cb_ignore_error\n    vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT\n    start_server(verify_mode: vflag, ignore_listener_error: true) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.client_cert_cb = -> ssl {\n        raise \"exception in client_cert_cb must be suppressed\"\n      }\n      # 1. Exception in client_cert_cb is suppressed\n      # 2. No client certificate will be sent to the server\n      # 3. SSL_VERIFY_FAIL_IF_NO_PEER_CERT causes the handshake to fail\n      assert_handshake_error {\n        server_connect(port, ctx) { |ssl| ssl.puts(\"abc\"); ssl.gets }\n      }\n    end\n  end\n\n  def test_client_ca\n    pend \"LibreSSL doesn't support certificate_authorities\" if libressl?\n\n    ctx_proc = Proc.new do |ctx|\n      store = OpenSSL::X509::Store.new\n      store.add_cert(@ca_cert)\n      store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT\n      ctx.cert_store = store\n      ctx.client_ca = [@ca_cert]\n    end\n\n    vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT\n    start_server(verify_mode: vflag, ctx_proc: ctx_proc) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      client_ca_from_server = nil\n      ctx.client_cert_cb = Proc.new do |sslconn|\n        client_ca_from_server = sslconn.client_ca\n        [@cli_cert, @cli_key]\n      end\n      server_connect(port, ctx) { |ssl|\n        assert_equal([@ca], client_ca_from_server)\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n    }\n  end\n\n  def test_unstarted_session\n    start_server do |port|\n      sock = TCPSocket.new(\"127.0.0.1\", port)\n      ssl = OpenSSL::SSL::SSLSocket.new(sock)\n\n      assert_raise(OpenSSL::SSL::SSLError) { ssl.syswrite(\"data\") }\n      assert_raise(OpenSSL::SSL::SSLError) { ssl.sysread(1) }\n\n      ssl.connect\n      ssl.puts \"abc\"\n      assert_equal \"abc\\n\", ssl.gets\n    ensure\n      ssl&.close\n      sock&.close\n    end\n  end\n\n  def test_parallel\n    start_server { |port|\n      ssls = []\n      10.times{\n        sock = TCPSocket.new(\"127.0.0.1\", port)\n        ssl = OpenSSL::SSL::SSLSocket.new(sock)\n        ssl.connect\n        ssl.sync_close = true\n        ssls << ssl\n      }\n      str = \"x\" * 1000 + \"\\n\"\n      ITERATIONS.times{\n        ssls.each{|ssl|\n          ssl.puts(str)\n          assert_equal(str, ssl.gets)\n        }\n      }\n      ssls.each{|ssl| ssl.close }\n    }\n  end\n\n  def test_verify_result\n    start_server(ignore_listener_error: true) { |port|\n      sock = TCPSocket.new(\"127.0.0.1\", port)\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n      ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n      ssl.sync_close = true\n      begin\n        assert_raise(OpenSSL::SSL::SSLError){ ssl.connect }\n        assert_equal(OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, ssl.verify_result)\n      ensure\n        ssl.close\n      end\n    }\n\n    start_server { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n      ctx.verify_callback = Proc.new do |preverify_ok, store_ctx|\n        store_ctx.error = OpenSSL::X509::V_OK\n        true\n      end\n      server_connect(port, ctx) { |ssl|\n        assert_equal(OpenSSL::X509::V_OK, ssl.verify_result)\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n    }\n\n    start_server(ignore_listener_error: true) { |port|\n      sock = TCPSocket.new(\"127.0.0.1\", port)\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n      ctx.verify_callback = Proc.new do |preverify_ok, store_ctx|\n        store_ctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION\n        false\n      end\n      ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n      ssl.sync_close = true\n      begin\n        assert_raise(OpenSSL::SSL::SSLError){ ssl.connect }\n        assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, ssl.verify_result)\n      ensure\n        ssl.close\n      end\n    }\n  end\n\n  def test_exception_in_verify_callback_is_ignored\n    start_server(ignore_listener_error: true) { |port|\n      sock = TCPSocket.new(\"127.0.0.1\", port)\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n      ctx.verify_callback = Proc.new do |preverify_ok, store_ctx|\n        store_ctx.error = OpenSSL::X509::V_OK\n        raise RuntimeError\n      end\n      ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n      ssl.sync_close = true\n      begin\n        EnvUtil.suppress_warning do\n          # SSLError, not RuntimeError\n          assert_raise(OpenSSL::SSL::SSLError) { ssl.connect }\n        end\n        assert_equal(OpenSSL::X509::V_ERR_CERT_REJECTED, ssl.verify_result)\n      ensure\n        ssl.close\n      end\n    }\n  end\n\n  def test_ca_file\n    start_server(ignore_listener_error: true) { |port|\n      # X509_STORE is shared; setting ca_file to SSLContext affects store\n      store = OpenSSL::X509::Store.new\n      assert_equal false, store.verify(@svr_cert)\n\n      ctx = Tempfile.create(\"ca_cert.pem\") { |f|\n        f.puts(@ca_cert.to_pem)\n        f.close\n\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n        ctx.cert_store = store\n        ctx.ca_file = f.path\n        ctx.setup\n        ctx\n      }\n      assert_nothing_raised {\n        server_connect(port, ctx) { |ssl| ssl.puts(\"abc\"); ssl.gets }\n      }\n      assert_equal true, store.verify(@svr_cert)\n    }\n  end\n\n  def test_ca_file_not_found\n    path = Tempfile.create(\"ca_cert.pem\") { |f| f.path }\n    ctx = OpenSSL::SSL::SSLContext.new\n    ctx.ca_file = path\n    # OpenSSL >= 1.1.0: /no certificate or crl found/\n    assert_raise(OpenSSL::SSL::SSLError) {\n      ctx.setup\n    }\n  end\n\n  def test_finished_messages\n    server_finished = nil\n    server_peer_finished = nil\n    client_finished = nil\n    client_peer_finished = nil\n\n    start_server(accept_proc: proc { |server|\n      server_finished = server.finished_message\n      server_peer_finished = server.peer_finished_message\n    }) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE\n      server_connect(port, ctx) { |ssl|\n        ssl.puts \"abc\"; ssl.gets\n\n        client_finished = ssl.finished_message\n        client_peer_finished = ssl.peer_finished_message\n      }\n    }\n    assert_not_nil(server_finished)\n    assert_not_nil(client_finished)\n    assert_equal(server_finished, client_peer_finished)\n    assert_equal(server_peer_finished, client_finished)\n  end\n\n  def test_sslctx_set_params\n    ctx = OpenSSL::SSL::SSLContext.new\n    ctx.set_params\n\n    assert_equal OpenSSL::SSL::VERIFY_PEER, ctx.verify_mode\n    ciphers_names = ctx.ciphers.collect{|v, _, _, _| v }\n    assert ciphers_names.all?{|v| /A(EC)?DH/ !~ v }, \"anon ciphers are disabled\"\n    assert ciphers_names.all?{|v| /(RC4|MD5|EXP|DES(?!-EDE|-CBC3))/ !~ v }, \"weak ciphers are disabled\"\n    assert_equal 0, ctx.options & OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS\n    assert_equal OpenSSL::SSL::OP_NO_COMPRESSION,\n                 ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION\n  end\n\n  def test_post_connect_check_with_anon_ciphers\n    # DH missing the q value on unknown named parameters is not FIPS-approved.\n    omit_on_fips\n    omit \"AWS-LC does not support DHE ciphersuites\" if aws_lc?\n\n    ctx_proc = -> ctx {\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      ctx.ciphers = \"aNULL\"\n      ctx.tmp_dh = Fixtures.pkey(\"dh-1\")\n      ctx.security_level = 0\n    }\n\n    start_server(ctx_proc: ctx_proc) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      ctx.ciphers = \"aNULL\"\n      ctx.security_level = 0\n      server_connect(port, ctx) { |ssl|\n        assert_raise_with_message(OpenSSL::SSL::SSLError, /anonymous cipher suite/i) {\n          ssl.post_connection_check(\"localhost.localdomain\")\n        }\n      }\n    }\n  end\n\n  def test_post_connection_check\n    sslerr = OpenSSL::SSL::SSLError\n\n    start_server { |port|\n      server_connect(port) { |ssl|\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n\n        assert_raise(sslerr){ssl.post_connection_check(\"localhost.localdomain\")}\n        assert_raise(sslerr){ssl.post_connection_check(\"127.0.0.1\")}\n        assert(ssl.post_connection_check(\"localhost\"))\n        assert_raise(sslerr){ssl.post_connection_check(\"foo.example.com\")}\n\n        cert = ssl.peer_cert\n        assert(!OpenSSL::SSL.verify_certificate_identity(cert, \"localhost.localdomain\"))\n        assert(!OpenSSL::SSL.verify_certificate_identity(cert, \"127.0.0.1\"))\n        assert(OpenSSL::SSL.verify_certificate_identity(cert, \"localhost\"))\n        assert(!OpenSSL::SSL.verify_certificate_identity(cert, \"foo.example.com\"))\n      }\n    }\n\n    exts = [\n      [\"keyUsage\",\"keyEncipherment,digitalSignature\",true],\n      [\"subjectAltName\",\"DNS:localhost.localdomain,IP:127.0.0.1\",false],\n    ]\n    @svr_cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key)\n    start_server { |port|\n      server_connect(port) { |ssl|\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n\n        assert(ssl.post_connection_check(\"localhost.localdomain\"))\n        assert(ssl.post_connection_check(\"127.0.0.1\"))\n        assert_raise(sslerr){ssl.post_connection_check(\"localhost\")}\n        assert_raise(sslerr){ssl.post_connection_check(\"foo.example.com\")}\n\n        cert = ssl.peer_cert\n        assert(OpenSSL::SSL.verify_certificate_identity(cert, \"localhost.localdomain\"))\n        assert(OpenSSL::SSL.verify_certificate_identity(cert, \"127.0.0.1\"))\n        assert(!OpenSSL::SSL.verify_certificate_identity(cert, \"localhost\"))\n        assert(!OpenSSL::SSL.verify_certificate_identity(cert, \"foo.example.com\"))\n      }\n    }\n\n    exts = [\n      [\"keyUsage\",\"keyEncipherment,digitalSignature\",true],\n      [\"subjectAltName\",\"DNS:*.localdomain\",false],\n    ]\n    @svr_cert = issue_cert(@svr, @svr_key, 5, exts, @ca_cert, @ca_key)\n    start_server { |port|\n      server_connect(port) { |ssl|\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n\n        assert(ssl.post_connection_check(\"localhost.localdomain\"))\n        assert_raise(sslerr){ssl.post_connection_check(\"127.0.0.1\")}\n        assert_raise(sslerr){ssl.post_connection_check(\"localhost\")}\n        assert_raise(sslerr){ssl.post_connection_check(\"foo.example.com\")}\n        cert = ssl.peer_cert\n        assert(OpenSSL::SSL.verify_certificate_identity(cert, \"localhost.localdomain\"))\n        assert(!OpenSSL::SSL.verify_certificate_identity(cert, \"127.0.0.1\"))\n        assert(!OpenSSL::SSL.verify_certificate_identity(cert, \"localhost\"))\n        assert(!OpenSSL::SSL.verify_certificate_identity(cert, \"foo.example.com\"))\n      }\n    }\n  end\n\n  def test_verify_certificate_identity\n    [true, false].each do |criticality|\n      cert = create_null_byte_SAN_certificate(criticality)\n      assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, 'www.example.com'))\n      assert_equal(true,  OpenSSL::SSL.verify_certificate_identity(cert, \"www.example.com\\0.evil.com\"))\n      assert_equal(false, OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.255'))\n      assert_equal(true,  OpenSSL::SSL.verify_certificate_identity(cert, '192.168.7.1'))\n      assert_equal(true,  OpenSSL::SSL.verify_certificate_identity(cert, '13::17'))\n      assert_equal(false,  OpenSSL::SSL.verify_certificate_identity(cert, '13::18'))\n      assert_equal(true,  OpenSSL::SSL.verify_certificate_identity(cert, '13:0:0:0:0:0:0:17'))\n      assert_equal(false,  OpenSSL::SSL.verify_certificate_identity(cert, '44:0:0:0:0:0:0:17'))\n      assert_equal(true,  OpenSSL::SSL.verify_certificate_identity(cert, '0013:0000:0000:0000:0000:0000:0000:0017'))\n      assert_equal(false,  OpenSSL::SSL.verify_certificate_identity(cert, '1313:0000:0000:0000:0000:0000:0000:0017'))\n    end\n  end\n\n  def test_verify_hostname\n    assert_equal(true,  OpenSSL::SSL.verify_hostname(\"www.example.com\", \"*.example.com\"))\n    assert_equal(false, OpenSSL::SSL.verify_hostname(\"www.subdomain.example.com\", \"*.example.com\"))\n  end\n\n  def test_verify_wildcard\n    assert_equal(false, OpenSSL::SSL.verify_wildcard(\"foo\", \"x*\"))\n    assert_equal(true,  OpenSSL::SSL.verify_wildcard(\"foo\", \"foo\"))\n    assert_equal(true,  OpenSSL::SSL.verify_wildcard(\"foo\", \"f*\"))\n    assert_equal(true,  OpenSSL::SSL.verify_wildcard(\"foo\", \"*\"))\n    assert_equal(false, OpenSSL::SSL.verify_wildcard(\"abc*bcd\", \"abcd\"))\n    assert_equal(false, OpenSSL::SSL.verify_wildcard(\"xn--qdk4b9b\", \"x*\"))\n    assert_equal(false, OpenSSL::SSL.verify_wildcard(\"xn--qdk4b9b\", \"*--qdk4b9b\"))\n    assert_equal(true,  OpenSSL::SSL.verify_wildcard(\"xn--qdk4b9b\", \"xn--qdk4b9b\"))\n  end\n\n  # Comments in this test is excerpted from https://www.rfc-editor.org/rfc/rfc6125#page-27\n  def test_post_connection_check_wildcard_san\n    # case-insensitive ASCII comparison\n    # RFC 6125, section 6.4.1\n    #\n    # \"..matching of the reference identifier against the presented identifier\n    # is performed by comparing the set of domain name labels using a\n    # case-insensitive ASCII comparison, as clarified by [DNS-CASE] (e.g.,\n    # \"WWW.Example.Com\" would be lower-cased to \"www.example.com\" for\n    # comparison purposes)\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*.example.com'), 'www.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*.Example.COM'), 'www.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*.example.com'), 'WWW.Example.COM'))\n    # 1.  The client SHOULD NOT attempt to match a presented identifier in\n    #     which the wildcard character comprises a label other than the\n    #     left-most label (e.g., do not match bar.*.example.net).\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:www.*.com'), 'www.example.com'))\n    # 2.  If the wildcard character is the only character of the left-most\n    #     label in the presented identifier, the client SHOULD NOT compare\n    #     against anything but the left-most label of the reference\n    #     identifier (e.g., *.example.com would match foo.example.com but\n    #     not bar.foo.example.com or example.com).\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*.example.com'), 'foo.example.com'))\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*.example.com'), 'bar.foo.example.com'))\n    # 3.  The client MAY match a presented identifier in which the wildcard\n    #     character is not the only character of the label (e.g.,\n    #     baz*.example.net and *baz.example.net and b*z.example.net would\n    #     be taken to match baz1.example.net and foobaz.example.net and\n    #     buzz.example.net, respectively).  ...\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:baz*.example.com'), 'baz1.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*baz.example.com'), 'foobaz.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:b*z.example.com'), 'buzz.example.com'))\n\n    # Section 6.4.3 of RFC6125 states that client should NOT match identifier\n    # where wildcard is other than left-most label.\n    #\n    # Also implicitly mentions the wildcard character only in singular form,\n    # and discourages matching against more than one wildcard.\n    #\n    # See RFC 6125, section 7.2, subitem 2.\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*b*.example.com'), 'abc.example.com'))\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*b*.example.com'), 'ab.example.com'))\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:*b*.example.com'), 'bc.example.com'))\n    #                                ...  However, the client SHOULD NOT\n    #   attempt to match a presented identifier where the wildcard\n    #   character is embedded within an A-label or U-label [IDNA-DEFS] of\n    #   an internationalized domain name [IDNA-PROTO].\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:xn*.example.com'), 'xn1ca.example.com'))\n    # part of A-label\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:xn--*.example.com'), 'xn--1ca.example.com'))\n    # part of U-label\n    # dNSName in RFC5280 is an IA5String so U-label should NOT be allowed\n    # regardless of wildcard.\n    #\n    # See Section 7.2 of RFC 5280:\n    #   IA5String is limited to the set of ASCII characters.\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_san('DNS:á*.example.com'), 'á1.example.com'))\n  end\n\n  def test_post_connection_check_wildcard_cn\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*.example.com'), 'www.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*.Example.COM'), 'www.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*.example.com'), 'WWW.Example.COM'))\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('www.*.com'), 'www.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*.example.com'), 'foo.example.com'))\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*.example.com'), 'bar.foo.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('baz*.example.com'), 'baz1.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*baz.example.com'), 'foobaz.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('b*z.example.com'), 'buzz.example.com'))\n    # Section 6.4.3 of RFC6125 states that client should NOT match identifier\n    # where wildcard is other than left-most label.\n    #\n    # Also implicitly mentions the wildcard character only in singular form,\n    # and discourages matching against more than one wildcard.\n    #\n    # See RFC 6125, section 7.2, subitem 2.\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*b*.example.com'), 'abc.example.com'))\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*b*.example.com'), 'ab.example.com'))\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('*b*.example.com'), 'bc.example.com'))\n    assert_equal(true, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('xn*.example.com'), 'xn1ca.example.com'))\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('xn--*.example.com'), 'xn--1ca.example.com'))\n    # part of U-label\n    # Subject in RFC5280 states case-insensitive ASCII comparison.\n    #\n    # See Section 7.2 of RFC 5280:\n    #   IA5String is limited to the set of ASCII characters.\n    assert_equal(false, OpenSSL::SSL.verify_certificate_identity(\n      create_cert_with_name('á*.example.com'), 'á1.example.com'))\n  end\n\n  def create_cert_with_san(san)\n    cert = OpenSSL::X509::Certificate.new\n    cert.subject = OpenSSL::X509::Name.parse(\"/DC=some/DC=site/CN=Some Site\")\n    v = OpenSSL::ASN1::Sequence(san.split(\",\").map { |item|\n      type, value = item.split(\":\", 2)\n      case type\n      when \"DNS\" then OpenSSL::ASN1::IA5String(value, 2, :IMPLICIT)\n      when \"IP\" then OpenSSL::ASN1::OctetString(IPAddr.new(value).hton, 7, :IMPLICIT)\n      else raise \"unsupported\"\n      end\n    })\n    cert.add_extension(OpenSSL::X509::Extension.new(\"subjectAltName\", v))\n    cert\n  end\n\n  def create_cert_with_name(name)\n    cert = OpenSSL::X509::Certificate.new\n    cert.subject = OpenSSL::X509::Name.new([['DC', 'some'], ['DC', 'site'], ['CN', name]])\n    cert\n  end\n\n\n  # Create NULL byte SAN certificate\n  def create_null_byte_SAN_certificate(critical = false)\n    ef = OpenSSL::X509::ExtensionFactory.new\n    cert = OpenSSL::X509::Certificate.new\n    cert.subject = OpenSSL::X509::Name.parse \"/DC=some/DC=site/CN=Some Site\"\n    ext = ef.create_ext('subjectAltName', 'DNS:placeholder,IP:192.168.7.1,IP:13::17', critical)\n    ext_asn1 = OpenSSL::ASN1.decode(ext.to_der)\n    san_list_der = ext_asn1.value.reduce(nil) { |memo,val| val.tag == 4 ? val.value : memo }\n    san_list_asn1 = OpenSSL::ASN1.decode(san_list_der)\n    san_list_asn1.value[0].value = \"www.example.com\\0.evil.com\"\n    pos = critical ? 2 : 1\n    ext_asn1.value[pos].value = san_list_asn1.to_der\n    real_ext = OpenSSL::X509::Extension.new ext_asn1\n    cert.add_extension(real_ext)\n    cert\n  end\n\n  def socketpair\n    if defined? UNIXSocket\n      UNIXSocket.pair\n    else\n      Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM, 0)\n    end\n  end\n\n  def test_keylog_cb\n    omit \"Keylog callback is not supported\" if libressl?\n\n    prefix = 'CLIENT_RANDOM'\n    context = OpenSSL::SSL::SSLContext.new\n    context.min_version = context.max_version = OpenSSL::SSL::TLS1_2_VERSION\n\n    cb_called = false\n    context.keylog_cb = proc do |_sock, line|\n      cb_called = true\n      assert_equal(prefix, line.split.first)\n    end\n\n    start_server do |port|\n      server_connect(port, context) do |ssl|\n        ssl.puts \"abc\"\n        assert_equal(\"abc\\n\", ssl.gets)\n        assert_equal(true, cb_called)\n      end\n    end\n\n    prefixes = [\n      'SERVER_HANDSHAKE_TRAFFIC_SECRET',\n      'EXPORTER_SECRET',\n      'SERVER_TRAFFIC_SECRET_0',\n      'CLIENT_HANDSHAKE_TRAFFIC_SECRET',\n      'CLIENT_TRAFFIC_SECRET_0',\n    ]\n    context = OpenSSL::SSL::SSLContext.new\n    context.min_version = context.max_version = OpenSSL::SSL::TLS1_3_VERSION\n    cb_called = false\n    context.keylog_cb = proc do |_sock, line|\n      cb_called = true\n      assert_not_nil(prefixes.delete(line.split.first))\n    end\n\n    start_server do |port|\n      server_connect(port, context) do |ssl|\n        ssl.puts \"abc\"\n        assert_equal(\"abc\\n\", ssl.gets)\n        assert_equal(true, cb_called)\n      end\n      assert_equal(0, prefixes.size)\n    end\n  end\n\n  def test_tlsext_hostname\n    fooctx = OpenSSL::SSL::SSLContext.new\n    fooctx.cert = @cli_cert\n    fooctx.key = @cli_key\n\n    ctx_proc = proc { |ctx|\n      ctx.servername_cb = proc { |ssl, servername|\n        case servername\n        when \"foo.example.com\"\n          fooctx\n        when \"bar.example.com\"\n          nil\n        else\n          raise \"unreachable\"\n        end\n      }\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      sock = TCPSocket.new(\"127.0.0.1\", port)\n      begin\n        ssl = OpenSSL::SSL::SSLSocket.new(sock)\n        ssl.hostname = \"foo.example.com\"\n        ssl.connect\n        assert_equal @cli_cert.serial, ssl.peer_cert.serial\n        assert_predicate fooctx, :frozen?\n\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      ensure\n        ssl&.close\n        sock.close\n      end\n\n      sock = TCPSocket.new(\"127.0.0.1\", port)\n      begin\n        ssl = OpenSSL::SSL::SSLSocket.new(sock)\n        ssl.hostname = \"bar.example.com\"\n        ssl.connect\n        assert_equal @svr_cert.serial, ssl.peer_cert.serial\n\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      ensure\n        ssl&.close\n        sock.close\n      end\n    end\n  end\n\n  def test_servername_cb_exception\n    sock1, sock2 = socketpair\n\n    t = Thread.new {\n      s1 = OpenSSL::SSL::SSLSocket.new(sock1)\n      s1.hostname = \"localhost\"\n      assert_raise_with_message(OpenSSL::SSL::SSLError, /unrecognized.name/i) {\n        s1.connect\n      }\n    }\n\n    ctx2 = OpenSSL::SSL::SSLContext.new\n    ctx2.servername_cb = lambda { |args| raise RuntimeError, \"foo\" }\n    s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)\n    assert_raise_with_message(RuntimeError, \"foo\") { s2.accept }\n    assert t.join\n  ensure\n    sock1.close\n    sock2.close\n    t.kill.join\n  end\n\n  def test_servername_cb_raises_an_exception_on_unknown_objects\n    sock1, sock2 = socketpair\n\n    t = Thread.new {\n      s1 = OpenSSL::SSL::SSLSocket.new(sock1)\n      s1.hostname = \"localhost\"\n      assert_raise(OpenSSL::SSL::SSLError) { s1.connect }\n    }\n\n    ctx2 = OpenSSL::SSL::SSLContext.new\n    ctx2.servername_cb = lambda { |args| Object.new }\n    s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)\n    assert_raise(ArgumentError) { s2.accept }\n    assert t.join\n  ensure\n    sock1.close\n    sock2.close\n    t.kill.join\n  end\n\n  def test_accept_errors_include_peeraddr\n    context = OpenSSL::SSL::SSLContext.new\n    context.cert = @svr_cert\n    context.key = @svr_key\n\n    server = TCPServer.new(\"127.0.0.1\", 0)\n    port = server.connect_address.ip_port\n\n    ssl_server = OpenSSL::SSL::SSLServer.new(server, context)\n\n    t = Thread.new do\n      assert_raise_with_message(OpenSSL::SSL::SSLError, /peeraddr=127\\.0\\.0\\.1/) do\n        ssl_server.accept\n      end\n    end\n\n    sock = TCPSocket.new(\"127.0.0.1\", port)\n    sock << \"\\x00\" * 1024\n\n    assert t.join\n  ensure\n    sock&.close\n    server.close\n  end\n\n  def test_verify_hostname_on_connect\n    ctx_proc = proc { |ctx|\n      exts = [\n        [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n        [\"subjectAltName\", \"DNS:a.example.com,DNS:*.b.example.com,\" \\\n                           \"DNS:c*.example.com,DNS:d.*.example.com\"],\n      ]\n      ctx.cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key)\n      ctx.key = @svr_key\n    }\n\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      assert_equal false, ctx.verify_hostname\n      ctx.verify_hostname = true\n      ctx.cert_store = OpenSSL::X509::Store.new\n      ctx.cert_store.add_cert(@ca_cert)\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n\n      [\n        [\"a.example.com\", true],\n        [\"A.Example.Com\", true],\n        [\"x.example.com\", false],\n        [\"b.example.com\", false],\n        [\"x.b.example.com\", true],\n        [\"cx.example.com\", true],\n        [\"d.x.example.com\", false],\n      ].each do |name, expected_ok|\n        begin\n          sock = TCPSocket.new(\"127.0.0.1\", port)\n          ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n          ssl.hostname = name\n          if expected_ok\n            ssl.connect\n            ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n          else\n            assert_raise(OpenSSL::SSL::SSLError) { ssl.connect }\n          end\n        ensure\n          ssl.close if ssl\n          sock.close if sock\n        end\n      end\n    end\n  end\n\n  def test_verify_hostname_failure_error_code\n    ctx_proc = proc { |ctx|\n      exts = [\n        [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n        [\"subjectAltName\", \"DNS:a.example.com\"],\n      ]\n      ctx.cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key)\n      ctx.key = @svr_key\n    }\n\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|\n      verify_callback_ok = verify_callback_err = nil\n\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_hostname = true\n      ctx.cert_store = OpenSSL::X509::Store.new\n      ctx.cert_store.add_cert(@ca_cert)\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n      ctx.verify_callback = -> (preverify_ok, store_ctx) {\n        verify_callback_ok = preverify_ok\n        verify_callback_err = store_ctx.error\n        preverify_ok\n      }\n\n      begin\n        sock = TCPSocket.new(\"127.0.0.1\", port)\n        ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n        ssl.hostname = \"b.example.com\"\n        assert_raise(OpenSSL::SSL::SSLError) { ssl.connect }\n        assert_equal false, verify_callback_ok\n        assert_equal OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH, verify_callback_err\n      ensure\n        sock&.close\n      end\n    end\n  end\n\n  def test_connect_certificate_verify_failed_exception_message\n    start_server(ignore_listener_error: true) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.set_params\n      assert_raise_with_message(OpenSSL::SSL::SSLError, /unable to get local issuer certificate/) {\n        server_connect(port, ctx)\n      }\n    }\n\n    ctx_proc = proc { |ctx|\n      now = Time.now\n      ctx.cert = issue_cert(@svr, @svr_key, 30, [], @ca_cert, @ca_key,\n                            not_before: now - 7200, not_after: now - 3600)\n    }\n    start_server(ignore_listener_error: true, ctx_proc: ctx_proc) { |port|\n      store = OpenSSL::X509::Store.new\n      store.add_cert(@ca_cert)\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.set_params(cert_store: store)\n      assert_raise_with_message(OpenSSL::SSL::SSLError, /expired/) {\n        server_connect(port, ctx)\n      }\n    }\n  end\n\n  def test_unset_OP_ALL\n    ctx_proc = Proc.new { |ctx|\n      # If OP_DONT_INSERT_EMPTY_FRAGMENTS is not defined, this test is\n      # redundant because the default options already are equal to OP_ALL.\n      # But it also degrades gracefully, so keep it\n      ctx.options = OpenSSL::SSL::OP_ALL\n    }\n    start_server(ctx_proc: ctx_proc) { |port|\n      server_connect(port) { |ssl|\n        ssl.puts('hello')\n        assert_equal(\"hello\\n\", ssl.gets)\n      }\n    }\n  end\n\n  def check_supported_protocol_versions\n    possible_versions = [\n      OpenSSL::SSL::SSL3_VERSION,\n      OpenSSL::SSL::TLS1_VERSION,\n      OpenSSL::SSL::TLS1_1_VERSION,\n      OpenSSL::SSL::TLS1_2_VERSION,\n      OpenSSL::SSL::TLS1_3_VERSION,\n    ]\n\n    supported = []\n    ctx_proc = proc { |ctx|\n      # The default security level is 1 in OpenSSL <= 3.1, 2 in OpenSSL >= 3.2\n      # In OpenSSL >= 3.0, TLS 1.1 or older is disabled at level 1\n      ctx.security_level = 0\n      # Explicitly reset them to avoid influenced by OPENSSL_CONF\n      ctx.min_version = ctx.max_version = nil\n    }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|\n      possible_versions.each do |ver|\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.security_level = 0\n        ctx.min_version = ctx.max_version = ver\n        server_connect(port, ctx) { |ssl|\n          ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        }\n        supported << ver\n      rescue OpenSSL::SSL::SSLError, Errno::ECONNRESET\n      end\n    end\n\n    # Sanity check: in our test suite we assume these are always supported\n    assert_include(supported, OpenSSL::SSL::TLS1_2_VERSION)\n    assert_include(supported, OpenSSL::SSL::TLS1_3_VERSION)\n\n    supported\n  end\n\n  def test_set_params_min_version\n    supported = check_supported_protocol_versions\n    store = OpenSSL::X509::Store.new\n    store.add_cert(@ca_cert)\n\n    if supported.include?(OpenSSL::SSL::SSL3_VERSION)\n      # SSLContext#set_params properly disables SSL 3.0 by default\n      ctx_proc = proc { |ctx|\n        ctx.min_version = ctx.max_version = OpenSSL::SSL::SSL3_VERSION\n      }\n      start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.set_params(cert_store: store, verify_hostname: false)\n        assert_raise(OpenSSL::SSL::SSLError) { server_connect(port, ctx) }\n      }\n    end\n  end\n\n  def test_minmax_version\n    supported = check_supported_protocol_versions\n\n    # name: The string that would be returned by SSL_get_version()\n    # method: The version-specific method name (if any)\n    vmap = {\n      OpenSSL::SSL::SSL3_VERSION => { name: \"SSLv3\", method: \"SSLv3\" },\n      OpenSSL::SSL::SSL3_VERSION => { name: \"SSLv3\", method: \"SSLv3\" },\n      OpenSSL::SSL::TLS1_VERSION => { name: \"TLSv1\", method: \"TLSv1\" },\n      OpenSSL::SSL::TLS1_1_VERSION => { name: \"TLSv1.1\", method: \"TLSv1_1\" },\n      OpenSSL::SSL::TLS1_2_VERSION => { name: \"TLSv1.2\", method: \"TLSv1_2\" },\n      OpenSSL::SSL::TLS1_3_VERSION => { name: \"TLSv1.3\", method: nil },\n    }\n\n    # Server enables a single version\n    supported.each do |ver|\n      ctx_proc = proc { |ctx|\n        ctx.security_level = 0\n        ctx.min_version = ctx.max_version = ver\n      }\n      start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|\n        supported.each do |cver|\n          # Client enables a single version\n          ctx1 = OpenSSL::SSL::SSLContext.new\n          ctx1.security_level = 0\n          ctx1.min_version = ctx1.max_version = cver\n          if ver == cver\n            server_connect(port, ctx1) { |ssl|\n              assert_equal vmap[cver][:name], ssl.ssl_version\n              ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n            }\n          else\n            assert_raise(OpenSSL::SSL::SSLError) { server_connect(port, ctx1) }\n          end\n\n          # There is no version-specific SSL methods for TLS 1.3\n          if cver <= OpenSSL::SSL::TLS1_2_VERSION\n            # Client enables a single version using #ssl_version=\n            ctx2 = OpenSSL::SSL::SSLContext.new\n            ctx2.security_level = 0\n            ctx2.ssl_version = vmap[cver][:method]\n            if ver == cver\n              server_connect(port, ctx2) { |ssl|\n                assert_equal vmap[cver][:name], ssl.ssl_version\n                ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n              }\n            else\n              assert_raise(OpenSSL::SSL::SSLError) { server_connect(port, ctx2) }\n            end\n          end\n        end\n\n        # Client enables all supported versions\n        ctx3 = OpenSSL::SSL::SSLContext.new\n        ctx3.security_level = 0\n        ctx3.min_version = ctx3.max_version = nil\n        server_connect(port, ctx3) { |ssl|\n          assert_equal vmap[ver][:name], ssl.ssl_version\n          ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        }\n      }\n    end\n\n    if supported.size == 1\n      pend \"More than one protocol version must be supported\"\n    end\n\n    # Server sets min_version (earliest is disabled)\n    sver = supported[1]\n    ctx_proc = proc { |ctx|\n      ctx.security_level = 0\n      ctx.min_version = sver\n    }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|\n      supported.each do |cver|\n        # Client sets min_version\n        ctx1 = OpenSSL::SSL::SSLContext.new\n        ctx1.security_level = 0\n        ctx1.min_version = cver\n        ctx1.max_version = 0\n        server_connect(port, ctx1) { |ssl|\n          assert_equal vmap[supported.last][:name], ssl.ssl_version\n          ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        }\n\n        # Client sets max_version\n        ctx2 = OpenSSL::SSL::SSLContext.new\n        ctx2.security_level = 0\n        ctx2.min_version = 0\n        ctx2.max_version = cver\n        if cver >= sver\n          server_connect(port, ctx2) { |ssl|\n            assert_equal vmap[cver][:name], ssl.ssl_version\n            ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n          }\n        else\n          assert_raise(OpenSSL::SSL::SSLError) { server_connect(port, ctx2) }\n        end\n      end\n    }\n\n    # Server sets max_version (latest is disabled)\n    sver = supported[-2]\n    ctx_proc = proc { |ctx|\n      ctx.security_level = 0\n      ctx.min_version = 0\n      ctx.max_version = sver\n    }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|\n      supported.each do |cver|\n        # Client sets min_version\n        ctx1 = OpenSSL::SSL::SSLContext.new\n        ctx1.min_version = cver\n        if cver <= sver\n          server_connect(port, ctx1) { |ssl|\n            assert_equal vmap[sver][:name], ssl.ssl_version\n            ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n          }\n        else\n          assert_raise(OpenSSL::SSL::SSLError) { server_connect(port, ctx1) }\n        end\n\n        # Client sets max_version\n        ctx2 = OpenSSL::SSL::SSLContext.new\n        ctx2.security_level = 0\n        ctx2.min_version = 0\n        ctx2.max_version = cver\n        server_connect(port, ctx2) { |ssl|\n          if cver >= sver\n            assert_equal vmap[sver][:name], ssl.ssl_version\n          else\n            assert_equal vmap[cver][:name], ssl.ssl_version\n          end\n          ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        }\n      end\n    }\n  end\n\n  def test_minmax_version_system_default\n    omit \"LibreSSL and AWS-LC do not support OPENSSL_CONF\" if libressl? || aws_lc?\n\n    Tempfile.create(\"openssl.cnf\") { |f|\n      f.puts(<<~EOF)\n        openssl_conf = default_conf\n        [default_conf]\n        ssl_conf = ssl_sect\n        [ssl_sect]\n        system_default = ssl_default_sect\n        [ssl_default_sect]\n        MaxProtocol = TLSv1.2\n      EOF\n      f.close\n\n      start_server(ignore_listener_error: true) do |port|\n        assert_separately([{ \"OPENSSL_CONF\" => f.path }, \"-ropenssl\", \"-\", port.to_s], <<~\"end;\")\n          sock = TCPSocket.new(\"127.0.0.1\", ARGV[0].to_i)\n          ctx = OpenSSL::SSL::SSLContext.new\n          ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION\n          ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n          ssl.sync_close = true\n          ssl.connect\n          assert_equal(\"TLSv1.2\", ssl.ssl_version)\n          ssl.puts(\"abc\"); assert_equal(\"abc\\n\", ssl.gets)\n          ssl.close\n        end;\n\n        assert_separately([{ \"OPENSSL_CONF\" => f.path }, \"-ropenssl\", \"-\", port.to_s], <<~\"end;\")\n          sock = TCPSocket.new(\"127.0.0.1\", ARGV[0].to_i)\n          ctx = OpenSSL::SSL::SSLContext.new\n          ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION\n          ctx.max_version = nil\n          ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n          ssl.sync_close = true\n          ssl.connect\n          assert_equal(\"TLSv1.3\", ssl.ssl_version)\n          ssl.puts(\"abc\"); assert_equal(\"abc\\n\", ssl.gets)\n          ssl.close\n        end;\n      end\n    }\n  end\n\n  def test_respect_system_default_min\n    omit \"LibreSSL and AWS-LC do not support OPENSSL_CONF\" if libressl? || aws_lc?\n\n    Tempfile.create(\"openssl.cnf\") { |f|\n      f.puts(<<~EOF)\n        openssl_conf = default_conf\n        [default_conf]\n        ssl_conf = ssl_sect\n        [ssl_sect]\n        system_default = ssl_default_sect\n        [ssl_default_sect]\n        MinProtocol = TLSv1.3\n      EOF\n      f.close\n\n      ctx_proc = proc { |ctx|\n        ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      }\n      start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|\n        assert_separately([{ \"OPENSSL_CONF\" => f.path }, \"-ropenssl\", \"-\", port.to_s], <<~\"end;\")\n          sock = TCPSocket.new(\"127.0.0.1\", ARGV[0].to_i)\n          ctx = OpenSSL::SSL::SSLContext.new\n          ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n          ssl.sync_close = true\n          assert_raise(OpenSSL::SSL::SSLError) do\n            ssl.connect\n          end\n          ssl.close\n        end;\n      end\n\n      ctx_proc = proc { |ctx|\n        ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION\n      }\n      start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|\n        assert_separately([{ \"OPENSSL_CONF\" => f.path }, \"-ropenssl\", \"-\", port.to_s], <<~\"end;\")\n          sock = TCPSocket.new(\"127.0.0.1\", ARGV[0].to_i)\n          ctx = OpenSSL::SSL::SSLContext.new\n          ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n          ssl.sync_close = true\n          ssl.connect\n          assert_equal(\"TLSv1.3\", ssl.ssl_version)\n          ssl.puts(\"abc\"); assert_equal(\"abc\\n\", ssl.gets)\n          ssl.close\n        end;\n      end\n    }\n  end\n\n  def test_options_disable_versions\n    # It's recommended to use SSLContext#{min,max}_version= instead in real\n    # applications. The purpose of this test case is to check that SSL options\n    # are properly propagated to OpenSSL library.\n    supported = check_supported_protocol_versions\n    if !supported.include?(OpenSSL::SSL::TLS1_2_VERSION) ||\n        !supported.include?(OpenSSL::SSL::TLS1_3_VERSION)\n      pend \"this test case requires both TLS 1.2 and TLS 1.3 to be supported \" \\\n        \"and enabled by default\"\n    end\n\n    # Server disables TLS 1.2 and earlier\n    ctx_proc = proc { |ctx|\n      ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 |\n        OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 |\n        OpenSSL::SSL::OP_NO_TLSv1_2\n    }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|\n      # Client only supports TLS 1.2\n      ctx1 = OpenSSL::SSL::SSLContext.new\n      ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      assert_raise(OpenSSL::SSL::SSLError) { server_connect(port, ctx1) }\n\n      # Client only supports TLS 1.3\n      ctx2 = OpenSSL::SSL::SSLContext.new\n      ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_3_VERSION\n      assert_nothing_raised { server_connect(port, ctx2) { } }\n    }\n\n    # Server only supports TLS 1.2\n    ctx_proc = proc { |ctx|\n      ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n    }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|\n      # Client doesn't support TLS 1.2\n      ctx1 = OpenSSL::SSL::SSLContext.new\n      ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_2\n      assert_raise(OpenSSL::SSL::SSLError) { server_connect(port, ctx1) }\n\n      # Client supports TLS 1.2 by default\n      ctx2 = OpenSSL::SSL::SSLContext.new\n      ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_3\n      assert_nothing_raised { server_connect(port, ctx2) { } }\n    }\n  end\n\n  def test_ssl_methods_constant\n    EnvUtil.suppress_warning { # Deprecated in v2.1.0\n      base = [:TLSv1_2, :TLSv1_1, :TLSv1, :SSLv3, :SSLv2, :SSLv23]\n      base.each do |name|\n        assert_include OpenSSL::SSL::SSLContext::METHODS, name\n        assert_include OpenSSL::SSL::SSLContext::METHODS, :\"#{name}_client\"\n        assert_include OpenSSL::SSL::SSLContext::METHODS, :\"#{name}_server\"\n      end\n    }\n  end\n\n  def test_renegotiation_cb\n    num_handshakes = 0\n    renegotiation_cb = Proc.new { |ssl| num_handshakes += 1 }\n    ctx_proc = Proc.new { |ctx| ctx.renegotiation_cb = renegotiation_cb }\n    start_server(ctx_proc: ctx_proc) { |port|\n      server_connect(port) { |ssl|\n        assert_equal(1, num_handshakes)\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n    }\n  end\n\n  def test_alpn_protocol_selection_ary\n    advertised = [\"http/1.1\", \"spdy/2\"]\n    ctx_proc = Proc.new { |ctx|\n      ctx.alpn_select_cb = -> (protocols) {\n        protocols.first\n      }\n      ctx.alpn_protocols = advertised\n    }\n    start_server(ctx_proc: ctx_proc) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.alpn_protocols = advertised\n      server_connect(port, ctx) { |ssl|\n        assert_equal(advertised.first, ssl.alpn_protocol)\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n    }\n  end\n\n  def test_alpn_protocol_selection_cancel\n    sock1, sock2 = socketpair\n\n    ctx1 = OpenSSL::SSL::SSLContext.new\n    ctx1.cert = @svr_cert\n    ctx1.key = @svr_key\n    ctx1.alpn_select_cb = -> (protocols) { nil }\n    ssl1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)\n\n    ctx2 = OpenSSL::SSL::SSLContext.new\n    ctx2.alpn_protocols = [\"http/1.1\"]\n    ssl2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)\n\n    t = Thread.new {\n      ssl2.connect_nonblock(exception: false)\n    }\n    assert_raise_with_message(TypeError, /nil/) { ssl1.accept }\n    t.join\n  ensure\n    sock1&.close\n    sock2&.close\n    ssl1&.close\n    ssl2&.close\n    t&.kill\n    t&.join\n  end\n\n  def test_npn_protocol_selection_ary\n    return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb)\n\n    advertised = [\"http/1.1\", \"spdy/2\"]\n    ctx_proc = proc { |ctx| ctx.npn_protocols = advertised }\n    start_server(ctx_proc: ctx_proc) { |port|\n      selector = lambda { |which|\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.max_version = :TLS1_2\n        ctx.npn_select_cb = -> (protocols) { protocols.send(which) }\n        server_connect(port, ctx) { |ssl|\n          assert_equal(advertised.send(which), ssl.npn_protocol)\n        }\n      }\n      selector.call(:first)\n      selector.call(:last)\n    }\n  end\n\n  def test_npn_protocol_selection_enum\n    return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb)\n\n    advertised = Object.new\n    def advertised.each\n      yield \"http/1.1\"\n      yield \"spdy/2\"\n    end\n    ctx_proc = Proc.new { |ctx| ctx.npn_protocols = advertised }\n    start_server(ctx_proc: ctx_proc) { |port|\n      selector = lambda { |selected, which|\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.max_version = :TLS1_2\n        ctx.npn_select_cb = -> (protocols) { protocols.to_a.send(which) }\n        server_connect(port, ctx) { |ssl|\n          assert_equal(selected, ssl.npn_protocol)\n        }\n      }\n      selector.call(\"http/1.1\", :first)\n      selector.call(\"spdy/2\", :last)\n    }\n  end\n\n  def test_npn_protocol_selection_cancel\n    return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb)\n\n    ctx_proc = Proc.new { |ctx| ctx.npn_protocols = [\"http/1.1\"] }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.max_version = :TLS1_2\n      ctx.npn_select_cb = -> (protocols) { raise RuntimeError.new }\n      assert_raise(RuntimeError) { server_connect(port, ctx) }\n    }\n  end\n\n  def test_npn_advertised_protocol_too_long\n    return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb)\n\n    ctx = OpenSSL::SSL::SSLContext.new\n    assert_raise(OpenSSL::SSL::SSLError) do\n      ctx.npn_protocols = [\"a\" * 256]\n      ctx.setup\n    end\n  end\n\n  def test_npn_selected_protocol_too_long\n    return unless OpenSSL::SSL::SSLContext.method_defined?(:npn_select_cb)\n\n    ctx_proc = Proc.new { |ctx| ctx.npn_protocols = [\"http/1.1\"] }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.max_version = :TLS1_2\n      ctx.npn_select_cb = -> (protocols) { \"a\" * 256 }\n      assert_raise(OpenSSL::SSL::SSLError) { server_connect(port, ctx) }\n    }\n  end\n\n  def readwrite_loop_safe(ctx, ssl)\n    readwrite_loop(ctx, ssl)\n  rescue OpenSSL::SSL::SSLError\n  end\n\n  def test_close_after_socket_close\n    start_server(server_proc: method(:readwrite_loop_safe)) { |port|\n      sock = TCPSocket.new(\"127.0.0.1\", port)\n      ssl = OpenSSL::SSL::SSLSocket.new(sock)\n      ssl.connect\n      ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      sock.close\n      assert_nothing_raised do\n        ssl.close\n      end\n    }\n  end\n\n  def test_sync_close_without_connect\n    Socket.open(:INET, :STREAM) {|s|\n      ssl = OpenSSL::SSL::SSLSocket.new(s)\n      ssl.sync_close = true\n      ssl.close\n      assert(s.closed?)\n    }\n  end\n\n  def test_get_ephemeral_key\n    # kRSA is not FIPS-approved.\n    omit_on_fips\n\n    # kRSA\n    ctx_proc1 = proc { |ctx|\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      ctx.ciphers = \"kRSA\"\n    }\n    start_server(ctx_proc: ctx_proc1, ignore_listener_error: true) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      ctx.ciphers = \"kRSA\"\n      begin\n        server_connect(port, ctx) { |ssl| assert_nil ssl.tmp_key }\n      rescue OpenSSL::SSL::SSLError\n        # kRSA seems disabled\n        raise unless $!.message =~ /no cipher/\n      end\n    end\n\n    # DHE\n    # OpenSSL 3.0 added support for named FFDHE groups in TLS 1.3\n    # LibreSSL does not support named FFDHE groups currently\n    # AWS-LC does not support DHE ciphersuites\n    if openssl?(3, 0, 0)\n      start_server do |port|\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.groups = \"ffdhe3072\"\n        server_connect(port, ctx) { |ssl|\n          assert_instance_of OpenSSL::PKey::DH, ssl.tmp_key\n          assert_equal 3072, ssl.tmp_key.p.num_bits\n          ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        }\n      end\n    end\n\n    # ECDHE\n    ctx_proc3 = proc { |ctx|\n      ctx.groups = \"P-256\"\n    }\n    start_server(ctx_proc: ctx_proc3) do |port|\n      server_connect(port) { |ssl|\n        assert_instance_of OpenSSL::PKey::EC, ssl.tmp_key\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n    end\n  end\n\n  def test_fallback_scsv\n    supported = check_supported_protocol_versions\n    unless supported.include?(OpenSSL::SSL::TLS1_1_VERSION)\n      omit \"TLS 1.1 support is required to run this test case\"\n    end\n\n    omit \"Fallback SCSV is not supported\" if libressl?\n\n    start_server do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      # Here is OK\n      # TLS1.2 supported and this is what we ask the first time\n      server_connect(port, ctx)\n    end\n\n    ctx_proc = proc { |ctx|\n      ctx.security_level = 0\n      ctx.min_version = 0\n      ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.enable_fallback_scsv\n      ctx.security_level = 0\n      ctx.min_version = 0\n      ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION\n      # Here is OK too\n      # TLS1.2 not supported, fallback to TLS1.1 and signaling the fallback\n      # Server doesn't support better, so connection OK\n      server_connect(port, ctx)\n    end\n\n    # Here is not OK\n    # TLS1.2 is supported, fallback to TLS1.1 (downgrade attack) and signaling the fallback\n    # Server support better, so refuse the connection\n    sock1, sock2 = socketpair\n    begin\n      # This test is for the downgrade protection mechanism of TLS1.2.\n      # This is why ctx1 bounds max_version == TLS1.2.\n      # Otherwise, this test fails when using openssl 1.1.1 (or later) that supports TLS1.3.\n      # TODO: We may need another test for TLS1.3 because it seems to have a different mechanism.\n      ctx1 = OpenSSL::SSL::SSLContext.new\n      ctx1.security_level = 0\n      ctx1.min_version = 0\n      ctx1.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1)\n\n      ctx2 = OpenSSL::SSL::SSLContext.new\n      ctx2.enable_fallback_scsv\n      ctx2.security_level = 0\n      ctx2.min_version = 0\n      ctx2.max_version = OpenSSL::SSL::TLS1_1_VERSION\n      s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2)\n      # AWS-LC has slightly different error messages in all-caps.\n      t = Thread.new {\n        assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback|INAPPROPRIATE_FALLBACK/) {\n          s2.connect\n        }\n      }\n      assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback|INAPPROPRIATE_FALLBACK/) {\n        s1.accept\n      }\n      t.join\n    ensure\n      sock1.close\n      sock2.close\n    end\n  end\n\n  def test_tmp_dh_callback\n    # DH missing the q value on unknown named parameters is not FIPS-approved.\n    omit_on_fips\n    omit \"AWS-LC does not support DHE ciphersuites\" if aws_lc?\n\n    dh = Fixtures.pkey(\"dh-1\")\n    called = false\n    ctx_proc = -> ctx {\n      ctx.max_version = :TLS1_2\n      ctx.ciphers = \"DH:!NULL\"\n      ctx.tmp_dh_callback = ->(*args) {\n        called = true\n        dh\n      }\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.groups = \"P-256\" # Exclude RFC 7919 groups\n      server_connect(port, ctx) { |ssl|\n        assert called, \"dh callback should be called\"\n        assert_equal dh.to_der, ssl.tmp_key.to_der\n      }\n    end\n  end\n\n  def test_ciphersuites_method_tls_connection\n    csuite = ['TLS_AES_128_GCM_SHA256', 'TLSv1.3', 128, 128]\n    inputs = [csuite[0], [csuite[0]], [csuite]]\n\n    start_server do |port|\n      inputs.each do |input|\n        cli_ctx = OpenSSL::SSL::SSLContext.new\n        cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION\n        cli_ctx.ciphersuites = input\n\n        server_connect(port, cli_ctx) do |ssl|\n          assert_equal('TLSv1.3', ssl.ssl_version)\n          assert_equal(csuite[0], ssl.cipher[0])\n          ssl.puts('abc'); assert_equal(\"abc\\n\", ssl.gets)\n        end\n      end\n    end\n  end\n\n  def test_ciphersuites_method_nil_argument\n    ssl_ctx = OpenSSL::SSL::SSLContext.new\n    assert_nothing_raised { ssl_ctx.ciphersuites = nil }\n  end\n\n  def test_ciphersuites_method_frozen_object\n    ssl_ctx = OpenSSL::SSL::SSLContext.new\n    ssl_ctx.freeze\n    assert_raise(FrozenError) { ssl_ctx.ciphersuites = 'TLS_AES_256_GCM_SHA384' }\n  end\n\n  def test_ciphersuites_method_bogus_csuite\n    ssl_ctx = OpenSSL::SSL::SSLContext.new\n    # AWS-LC has slightly different error messages in all-caps.\n    assert_raise_with_message(\n      OpenSSL::SSL::SSLError,\n      /SSL_CTX_set_ciphersuites: (no cipher match|NO_CIPHER_MATCH)/i\n    ) { ssl_ctx.ciphersuites = 'BOGUS' }\n  end\n\n  def test_ciphers_method_tls_connection\n    csuite = ['ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256, 256]\n    inputs = [csuite[0], [csuite[0]], [csuite]]\n\n    start_server do |port|\n      inputs.each do |input|\n        cli_ctx = OpenSSL::SSL::SSLContext.new\n        cli_ctx.min_version = cli_ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n        cli_ctx.ciphers = input\n\n        server_connect(port, cli_ctx) do |ssl|\n          assert_equal('TLSv1.2', ssl.ssl_version)\n          assert_equal(csuite[0], ssl.cipher[0])\n          ssl.puts('abc'); assert_equal(\"abc\\n\", ssl.gets)\n        end\n      end\n    end\n  end\n\n  def test_ciphers_method_nil_argument\n    ssl_ctx = OpenSSL::SSL::SSLContext.new\n    assert_nothing_raised { ssl_ctx.ciphers = nil }\n  end\n\n  def test_ciphers_method_frozen_object\n    ssl_ctx = OpenSSL::SSL::SSLContext.new\n\n    ssl_ctx.freeze\n    assert_raise(FrozenError) { ssl_ctx.ciphers = 'ECDHE-RSA-AES128-SHA' }\n  end\n\n  def test_ciphers_method_bogus_csuite\n    ssl_ctx = OpenSSL::SSL::SSLContext.new\n\n    # AWS-LC has slightly different error messages in all-caps.\n    assert_raise_with_message(\n      OpenSSL::SSL::SSLError,\n      /SSL_CTX_set_cipher_list: (no cipher match|NO_CIPHER_MATCH)/i\n    ) { ssl_ctx.ciphers = 'BOGUS' }\n  end\n\n  def test_sigalgs\n    omit \"SSL_CTX_set1_sigalgs_list() not supported\" if libressl?\n\n    svr_exts = [\n      [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n      [\"subjectAltName\", \"DNS:localhost\", false],\n    ]\n    ecdsa_key = Fixtures.pkey(\"p256\")\n    ecdsa_cert = issue_cert(@svr, ecdsa_key, 10, svr_exts, @ca_cert, @ca_key)\n\n    ctx_proc = -> ctx {\n      # Unset values set by start_server\n      ctx.cert = ctx.key = ctx.extra_chain_cert = nil\n      ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA\n      ctx.add_certificate(ecdsa_cert, ecdsa_key, [@ca_cert]) # ECDSA\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      ctx1 = OpenSSL::SSL::SSLContext.new\n      ctx1.sigalgs = \"rsa_pss_rsae_sha256\"\n      server_connect(port, ctx1) { |ssl|\n        assert_kind_of(OpenSSL::PKey::RSA, ssl.peer_cert.public_key)\n        ssl.puts(\"abc\"); ssl.gets\n      }\n\n      ctx2 = OpenSSL::SSL::SSLContext.new\n      ctx2.sigalgs = \"ed25519:ecdsa_secp256r1_sha256\"\n      server_connect(port, ctx2) { |ssl|\n        assert_kind_of(OpenSSL::PKey::EC, ssl.peer_cert.public_key)\n        ssl.puts(\"abc\"); ssl.gets\n      }\n    end\n\n    # Frozen\n    ssl_ctx = OpenSSL::SSL::SSLContext.new\n    ssl_ctx.freeze\n    assert_raise(FrozenError) { ssl_ctx.sigalgs = \"ECDSA+SHA256:RSA+SHA256\" }\n\n    # Bogus\n    ssl_ctx = OpenSSL::SSL::SSLContext.new\n    assert_raise(TypeError) { ssl_ctx.sigalgs = nil }\n    assert_raise(OpenSSL::SSL::SSLError) { ssl_ctx.sigalgs = \"BOGUS\" }\n  end\n\n  def test_client_sigalgs\n    omit \"SSL_CTX_set1_client_sigalgs_list() not supported\" if libressl? || aws_lc?\n\n    cli_exts = [\n      [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n      [\"subjectAltName\", \"DNS:localhost\", false],\n    ]\n    ecdsa_key = Fixtures.pkey(\"p256\")\n    ecdsa_cert = issue_cert(@cli, ecdsa_key, 10, cli_exts, @ca_cert, @ca_key)\n\n    ctx_proc = -> ctx {\n      store = OpenSSL::X509::Store.new\n      store.add_cert(@ca_cert)\n      store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT\n      ctx.cert_store = store\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT\n      ctx.client_sigalgs = \"ECDSA+SHA256\"\n    }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|\n      ctx1 = OpenSSL::SSL::SSLContext.new\n      ctx1.add_certificate(@cli_cert, @cli_key) # RSA\n      assert_handshake_error {\n        server_connect(port, ctx1) { |ssl|\n          ssl.puts(\"abc\"); ssl.gets\n        }\n      }\n\n      ctx2 = OpenSSL::SSL::SSLContext.new\n      ctx2.add_certificate(ecdsa_cert, ecdsa_key) # ECDSA\n      server_connect(port, ctx2) { |ssl|\n        ssl.puts(\"abc\"); ssl.gets\n      }\n    end\n  end\n\n  def test_get_sigalg\n    # SSL_get0_signature_name() not supported\n    # SSL_get0_peer_signature_name() not supported\n    return unless openssl?(3, 5, 0)\n\n    server_proc = -> (ctx, ssl) {\n      assert_equal('rsa_pss_rsae_sha256', ssl.sigalg)\n      assert_nil(ssl.peer_sigalg)\n\n      readwrite_loop(ctx, ssl)\n    }\n    start_server(server_proc: server_proc) do |port|\n      cli_ctx = OpenSSL::SSL::SSLContext.new\n      server_connect(port, cli_ctx) do |ssl|\n        assert_nil(ssl.sigalg)\n        assert_equal('rsa_pss_rsae_sha256', ssl.peer_sigalg)\n        ssl.puts \"abc\"; ssl.gets\n      end\n    end\n  end\n\n  def test_pqc_sigalg\n    # PQC algorithm ML-DSA (FIPS 204) is supported on OpenSSL 3.5 or later.\n    return unless openssl?(3, 5, 0)\n\n    mldsa = Fixtures.pkey(\"mldsa65-1\")\n    mldsa_ca_key  = Fixtures.pkey(\"mldsa65-2\")\n    mldsa_ca_cert = issue_cert(@ca, mldsa_ca_key, 1, @ca_exts, nil, nil,\n                               digest: nil)\n    mldsa_cert = issue_cert(@svr, mldsa, 60, [], mldsa_ca_cert, mldsa_ca_key,\n                            digest: nil)\n    rsa = Fixtures.pkey(\"rsa-1\")\n    rsa_cert = issue_cert(@svr, rsa, 61, [], @ca_cert, @ca_key)\n    ctx_proc = -> ctx {\n      # Unset values set by start_server\n      ctx.cert = ctx.key = ctx.extra_chain_cert = nil\n      ctx.sigalgs = \"rsa_pss_rsae_sha256:mldsa65\"\n      ctx.add_certificate(mldsa_cert, mldsa)\n      ctx.add_certificate(rsa_cert, rsa)\n    }\n\n    server_proc = -> (ctx, ssl) {\n      assert_equal('mldsa65', ssl.sigalg)\n\n      readwrite_loop(ctx, ssl)\n    }\n    start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      # Set signature algorithm because while OpenSSL may use ML-DSA by\n      # default, the system OpenSSL configuration affects the used signature\n      # algorithm.\n      ctx.sigalgs = 'mldsa65'\n      server_connect(port, ctx) { |ssl|\n        assert_equal('mldsa65', ssl.peer_sigalg)\n        ssl.puts \"abc\"; ssl.gets\n      }\n    end\n\n    server_proc = -> (ctx, ssl) {\n      assert_equal('rsa_pss_rsae_sha256', ssl.sigalg)\n\n      readwrite_loop(ctx, ssl)\n    }\n    start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.sigalgs = 'rsa_pss_rsae_sha256'\n      server_connect(port, ctx) { |ssl|\n        assert_equal('rsa_pss_rsae_sha256', ssl.peer_sigalg)\n        ssl.puts \"abc\"; ssl.gets\n      }\n    end\n  end\n\n  def test_connect_works_when_setting_dh_callback_to_nil\n    omit \"AWS-LC does not support DHE ciphersuites\" if aws_lc?\n\n    ctx_proc = -> ctx {\n      ctx.max_version = :TLS1_2\n      ctx.ciphers = \"DH:!NULL\" # use DH\n      ctx.tmp_dh_callback = nil\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      assert_nothing_raised { server_connect(port) { } }\n    end\n  end\n\n  def test_tmp_dh\n    # DH missing the q value on unknown named parameters is not FIPS-approved.\n    omit_on_fips\n    omit \"AWS-LC does not support DHE ciphersuites\" if aws_lc?\n\n    dh = Fixtures.pkey(\"dh-1\")\n    ctx_proc = -> ctx {\n      ctx.max_version = :TLS1_2\n      ctx.ciphers = \"DH:!NULL\" # use DH\n      ctx.tmp_dh = dh\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.groups = \"P-256\" # Exclude RFC 7919 groups\n      server_connect(port, ctx) { |ssl|\n        assert_equal dh.to_der, ssl.tmp_key.to_der\n      }\n    end\n  end\n\n  def test_set_groups_tls12\n    ctx_proc = -> ctx {\n      # Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      ctx.ciphers = \"kEECDH\"\n      ctx.groups = \"P-384:P-521\"\n    }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|\n      # Test 1: Client=P-256:P-384, Server=P-384:P-521 --> P-384\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.groups = \"P-256:P-384\"\n      server_connect(port, ctx) { |ssl|\n        cs = ssl.cipher[0]\n        assert_match (/\\AECDH/), cs\n        # SSL_get0_group_name() is supported on OpenSSL 3.2 or later.\n        assert_equal \"secp384r1\", ssl.group if openssl?(3, 2, 0)\n        assert_equal \"secp384r1\", ssl.tmp_key.group.curve_name\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n\n      # Test 2: Client=P-256, Server=P-521:P-384 --> Fail\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.groups = \"P-256\"\n      assert_raise(OpenSSL::SSL::SSLError) {\n        server_connect(port, ctx) { }\n      }\n\n      # Test 3: Client=P-521:P-384, Server=P-521:P-384 --> P-521\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.groups = \"P-521:P-384\"\n      server_connect(port, ctx) { |ssl|\n        assert_equal \"secp521r1\", ssl.tmp_key.group.curve_name\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n\n      # Test 4: #ecdh_curves= alias\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.ecdh_curves = \"P-256:P-384\"\n      server_connect(port, ctx) { |ssl|\n        assert_equal \"secp384r1\", ssl.tmp_key.group.curve_name\n      }\n    end\n  end\n\n  def test_set_groups_tls13\n    ctx_proc = -> ctx {\n      # Assume TLS 1.3 is enabled and chosen by default\n      ctx.groups = \"P-384:P-521\"\n    }\n    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.groups = \"P-256:P-384\" # disable P-521\n\n      server_connect(port, ctx) { |ssl|\n        assert_equal \"TLSv1.3\", ssl.ssl_version\n        # SSL_get0_group_name() is supported on OpenSSL 3.2 or later.\n        assert_equal \"secp384r1\", ssl.group if openssl?(3, 2, 0)\n        assert_equal \"secp384r1\", ssl.tmp_key.group.curve_name\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n      }\n    end\n  end\n\n  def test_pqc_group\n    # PQC algorithm ML-KEM (FIPS 203) is supported on OpenSSL 3.5 or later.\n    return unless openssl?(3, 5, 0)\n\n    [\n      'X25519MLKEM768',\n      'SecP256r1MLKEM768',\n      'SecP384r1MLKEM1024'\n    ].each do |group|\n      ctx_proc = -> ctx {\n        ctx.groups = group\n      }\n      start_server(ctx_proc: ctx_proc) do |port|\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.groups = group\n        server_connect(port, ctx) { |ssl|\n          assert_equal(group, ssl.group)\n          ssl.puts \"abc\"; ssl.gets\n        }\n      end\n    end\n  end\n\n  def test_security_level\n    ctx = OpenSSL::SSL::SSLContext.new\n    ctx.security_level = 1\n    if aws_lc? # AWS-LC does not support security levels.\n      assert_equal(0, ctx.security_level)\n      return\n    end\n    assert_equal(1, ctx.security_level)\n\n    # See SSL_CTX_set_security_level(3). Definitions of security levels may\n    # change in future OpenSSL versions. As of OpenSSL 1.1.0:\n    #  - Level 1 requires 160-bit ECC keys or 1024-bit RSA keys.\n    #  - Level 2 requires 224-bit ECC keys or 2048-bit RSA keys.\n    begin\n      ec112 = OpenSSL::PKey::EC.generate(\"secp112r1\")\n      ec112_cert = issue_cert(@svr, ec112, 50, [], @ca_cert, @ca_key)\n      ec192 = OpenSSL::PKey::EC.generate(\"prime192v1\")\n      ec192_cert = issue_cert(@svr, ec192, 51, [], @ca_cert, @ca_key)\n    rescue OpenSSL::PKey::PKeyError\n      # Distro-provided OpenSSL may refuse to generate small keys\n      return\n    end\n\n    assert_raise(OpenSSL::SSL::SSLError) {\n      ctx.add_certificate(ec112_cert, ec112)\n    }\n    assert_nothing_raised {\n      ctx.add_certificate(ec192_cert, ec192)\n    }\n    ctx.security_level = 2\n    assert_raise(OpenSSL::SSL::SSLError) {\n      # < 112 bits of security\n      ctx.add_certificate(ec192_cert, ec192)\n    }\n  end\n\n  def test_dup\n    ctx = OpenSSL::SSL::SSLContext.new\n    sock1, sock2 = socketpair\n    ssl = OpenSSL::SSL::SSLSocket.new(sock1, ctx)\n\n    assert_raise(NoMethodError) { ctx.dup }\n    assert_raise(NoMethodError) { ssl.dup }\n  ensure\n    ssl.close if ssl\n    sock1.close\n    sock2.close\n  end\n\n  def test_freeze_calls_setup\n    bug = \"[ruby/openssl#85]\"\n    start_server(ignore_listener_error: true) { |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n      ctx.freeze\n      assert_raise(OpenSSL::SSL::SSLError, bug) {\n        server_connect(port, ctx)\n      }\n    }\n  end\n\n  def test_fileno\n    ctx = OpenSSL::SSL::SSLContext.new\n    sock1, sock2 = socketpair\n\n    socket = OpenSSL::SSL::SSLSocket.new(sock1)\n    server = OpenSSL::SSL::SSLServer.new(sock2, ctx)\n\n    assert_equal socket.fileno, socket.to_io.fileno\n    assert_equal server.fileno, server.to_io.fileno\n  ensure\n    sock1.close\n    sock2.close\n  end\n\n  def test_export_keying_material\n    start_server do |port|\n      cli_ctx = OpenSSL::SSL::SSLContext.new\n      server_connect(port, cli_ctx) do |ssl|\n        assert_instance_of(String, ssl.export_keying_material('ttls keying material', 64))\n        assert_operator(64, :==, ssl.export_keying_material('ttls keying material', 64).b.length)\n        assert_operator(8, :==, ssl.export_keying_material('ttls keying material', 8).b.length)\n        assert_operator(5, :==, ssl.export_keying_material('test', 5, 'context').b.length)\n        ssl.puts \"abc\"; ssl.gets # workaround to make tests work on windows\n      end\n    end\n  end\n\n  # OpenSSL::Buffering requires $/ accessible from non-main Ractors (Ruby 4.0)\n  # https://bugs.ruby-lang.org/issues/21109\n  #\n  # Hangs on Windows\n  # https://bugs.ruby-lang.org/issues/21537\n  if respond_to?(:ractor) && RUBY_VERSION >= \"4.0\" && RUBY_PLATFORM !~ /mswin|mingw/\n    ractor\n    def test_ractor_client\n      start_server { |port|\n        s = Ractor.new(port, @ca_cert) { |port, ca_cert|\n          sock = TCPSocket.new(\"127.0.0.1\", port)\n          ctx = OpenSSL::SSL::SSLContext.new\n          ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER\n          ctx.cert_store = OpenSSL::X509::Store.new.tap { |store|\n            store.add_cert(ca_cert)\n          }\n          begin\n            ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n            ssl.connect\n            ssl.puts(\"abc\")\n            ssl.gets\n          ensure\n            ssl.close\n            sock.close\n          end\n        }.value\n        assert_equal(\"abc\\n\", s)\n      }\n    end\n\n    ractor\n    def test_ractor_set_params\n      # We cannot actually test default stores in the test suite as it depends\n      # on the environment, but at least check that it does not raise an\n      # exception\n      ok = Ractor.new {\n        ctx = OpenSSL::SSL::SSLContext.new\n        ctx.set_params\n        ctx.cert_store.kind_of?(OpenSSL::X509::Store)\n      }.value\n      assert(ok, \"ctx.cert_store is an instance of OpenSSL::X509::Store\")\n    end\n  end\n\n  private\n\n  def server_connect(port, ctx = nil)\n    sock = TCPSocket.new(\"127.0.0.1\", port)\n    ssl = ctx ? OpenSSL::SSL::SSLSocket.new(sock, ctx) : OpenSSL::SSL::SSLSocket.new(sock)\n    ssl.sync_close = true\n    ssl.connect\n    yield ssl if block_given?\n  ensure\n    if ssl\n      ssl.close\n    elsif sock\n      sock.close\n    end\n  end\n\n  def assert_handshake_error\n    # different OpenSSL versions react differently when facing a SSL/TLS version\n    # that has been marked as forbidden, therefore any of these may be raised\n    assert_raise(OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::EPIPE) {\n      yield\n    }\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_ssl_session.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL::SSL)\n\nclass OpenSSL::TestSSLSession < OpenSSL::SSLTestCase\n  def test_session\n    ctx_proc = proc { |ctx|\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      server_connect_with_session(port, nil, nil) { |ssl|\n        session = ssl.session\n        assert(session == OpenSSL::SSL::Session.new(session.to_pem))\n        assert(session == OpenSSL::SSL::Session.new(ssl))\n        session.timeout = 5\n        assert_equal(5, session.timeout)\n        assert_not_nil(session.time)\n        # SSL_SESSION_time keeps long value so we can't keep nsec fragment.\n        session.time = t1 = Time.now.to_i\n        assert_equal(Time.at(t1), session.time)\n        assert_not_nil(session.id)\n        pem = session.to_pem\n        assert_match(/\\A-----BEGIN SSL SESSION PARAMETERS-----/, pem)\n        assert_match(/-----END SSL SESSION PARAMETERS-----\\Z/, pem)\n        pem.gsub!(/-----(BEGIN|END) SSL SESSION PARAMETERS-----/, '').gsub!(/[\\r\\n]+/m, '')\n        assert_equal(session.to_der, pem.unpack1('m'))\n        assert_not_nil(session.to_text)\n      }\n    end\n  end\n\n  # PEM file updated to use TLS 1.2 with ECDHE-RSA-AES256-SHA.\n  DUMMY_SESSION = <<__EOS__\n-----BEGIN SSL SESSION PARAMETERS-----\nMIIDzQIBAQICAwMEAsAUBCAF219w9ZEV8dNA60cpEGOI34hJtIFbf3bkfzSgMyad\nMQQwyGLbkCxE4OiMLdKKem+pyh8V7ifoP7tCxhdmwoDlJxI1v6nVCjai+FGYuncy\nNNSWoQYCBE4DDWuiAwIBCqOCAo4wggKKMIIBcqADAgECAgECMA0GCSqGSIb3DQEB\nBQUAMD0xEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5\nLWxhbmcxCzAJBgNVBAMMAkNBMB4XDTExMDYyMzA5NTQ1MVoXDTExMDYyMzEwMjQ1\nMVowRDETMBEGCgmSJomT8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1Ynkt\nbGFuZzESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\niQKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7CxaKPERYHs\nk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/Q3geLv8Z\nD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQABoxIwEDAO\nBgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBACj5WhoZ/ODVeHpwgq1d\n8fW/13ICRYHYpv6dzlWihyqclGxbKMlMnaVCPz+4JaVtMz3QB748KJQgL3Llg3R1\nek+f+n1MBCMfFFsQXJ2gtLB84zD6UCz8aaCWN5/czJCd7xMz7fRLy3TOIW5boXAU\nzIa8EODk+477K1uznHm286ab0Clv+9d304hwmBZgkzLg6+31Of6d6s0E0rwLGiS2\nsOWYg34Y3r4j8BS9Ak4jzpoLY6cJ0QAKCOJCgmjGr4XHpyXMLbicp3ga1uSbwtVO\ngF/gTfpLhJC+y0EQ5x3Ftl88Cq7ZJuLBDMo/TLIfReJMQu/HlrTT7+LwtneSWGmr\nKkSkAgQApQMCAROqgcMEgcAuDkAVfj6QAJMz9yqTzW5wPFyty7CxUEcwKjUqj5UP\n/Yvky1EkRuM/eQfN7ucY+MUvMqv+R8ZSkHPsnjkBN5ChvZXjrUSZKFVjR4eFVz2V\njismLEJvIFhQh6pqTroRrOjMfTaM5Lwoytr2FTGobN9rnjIRsXeFQW1HLFbXn7Dh\n8uaQkMwIVVSGRB8T7t6z6WIdWruOjCZ6G5ASI5XoqAHwGezhLodZuvJEfsVyCF9y\nj+RBGfCFrrQbBdnkFI/ztgM=\n-----END SSL SESSION PARAMETERS-----\n__EOS__\n\n  # PEM file updated to use TLS 1.1 with ECDHE-RSA-AES256-SHA.\n  DUMMY_SESSION_NO_EXT = <<-__EOS__\n-----BEGIN SSL SESSION PARAMETERS-----\nMIIDCAIBAQICAwIEAsAUBCDyAW7rcpzMjDSosH+Tv6sukymeqgq3xQVVMez628A+\nlAQw9TrKzrIqlHEh6ltuQaqv/Aq83AmaAlogYktZgXAjOGnhX7ifJDNLMuCfQq53\nhPAaoQYCBE4iDeeiBAICASyjggKOMIICijCCAXKgAwIBAgIBAjANBgkqhkiG9w0B\nAQUFADA9MRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVi\neS1sYW5nMQswCQYDVQQDDAJDQTAeFw0xMTA3MTYyMjE3MTFaFw0xMTA3MTYyMjQ3\nMTFaMEQxEzARBgoJkiaJk/IsZAEZFgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5\nLWxhbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\ngYkCgYEAy8LEsNRApz7U/j5DoB4XBgO9Z8Atv5y/OVQRp0ag8Tqo1YewsWijxEWB\n7JOATwpBN267U4T1nPZIxxEEO7n/WNa2ws9JWsjah8ssEBFSxZqdXKSLf0N4Hi7/\nGQ/aYoaMCiQ8jA4jegK2FJmXM71uPe+jFN/peeBOpRfyXxRFOYcCAwEAAaMSMBAw\nDgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3DQEBBQUAA4IBAQA3TRzABRG3kz8jEEYr\ntDQqXgsxwTsLhTT5d1yF0D8uFw+y15hJAJnh6GJHjqhWBrF4zNoTApFo+4iIL6g3\nq9C3mUsxIVAHx41DwZBh/FI7J4FqlAoGOguu7892CNVY3ZZjc3AXMTdKjcNoWPzz\nFCdj5fNT24JMMe+ZdGZK97ChahJsdn/6B3j6ze9NK9mfYEbiJhejGTPLOFVHJCGR\nKYYZ3ZcKhLDr9ql4d7cCo1gBtemrmFQGPui7GttNEqmXqUKvV8mYoa8farf5i7T4\nL6a/gp2cVZTaDIS1HjbJsA/Ag7AajZqiN6LfqShNUVsrMZ+5CoV8EkBDTZPJ9MSr\na3EqpAIEAKUDAgET\n-----END SSL SESSION PARAMETERS-----\n__EOS__\n\n\n  def test_session_time\n    sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT)\n    sess.time = (now = Time.now)\n    assert_equal(now.to_i, sess.time.to_i)\n    sess.time = 1\n    assert_equal(1, sess.time.to_i)\n    sess.time = 1.2345\n    assert_equal(1, sess.time.to_i)\n    # Can OpenSSL handle t>2038y correctly? Version?\n    sess.time = 2**31 - 1\n    assert_equal(2**31 - 1, sess.time.to_i)\n  end\n\n  def test_session_timeout\n    sess = OpenSSL::SSL::Session.new(DUMMY_SESSION_NO_EXT)\n    assert_raise(TypeError) do\n      sess.timeout = Time.now\n    end\n    sess.timeout = 1\n    assert_equal(1, sess.timeout.to_i)\n    sess.timeout = 1.2345\n    assert_equal(1, sess.timeout.to_i)\n    sess.timeout = 2**31 - 1\n    assert_equal(2**31 - 1, sess.timeout.to_i)\n  end\n\n  def test_session_exts_read\n    assert(OpenSSL::SSL::Session.new(DUMMY_SESSION))\n  end\n\n  def test_resumption\n    non_resumable = nil\n    start_server { |port|\n      server_connect_with_session(port, nil, nil) { |ssl|\n        ssl.puts \"abc\"; assert_equal \"abc\\n\", ssl.gets\n        non_resumable = ssl.session\n      }\n    }\n\n    ctx_proc = proc { |ctx|\n      ctx.options &= ~OpenSSL::SSL::OP_NO_TICKET\n      # Disable server-side session cache which is enabled by default\n      ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF\n      # Session tickets must be retrieved via ctx.session_new_cb in TLS 1.3 in AWS-LC.\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl? || aws_lc?\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      sess1 = server_connect_with_session(port, nil, nil) { |ssl|\n        ssl.puts(\"abc\"); assert_equal \"abc\\n\", ssl.gets\n        assert_equal false, ssl.session_reused?\n        ssl.session\n      }\n\n      server_connect_with_session(port, nil, non_resumable) { |ssl|\n        ssl.puts(\"abc\"); assert_equal \"abc\\n\", ssl.gets\n        assert_equal false, ssl.session_reused?\n      }\n\n      server_connect_with_session(port, nil, sess1) { |ssl|\n        ssl.puts(\"abc\"); assert_equal \"abc\\n\", ssl.gets\n        assert_equal true, ssl.session_reused?\n      }\n    end\n  end\n\n  def test_server_session_cache\n    ctx_proc = Proc.new do |ctx|\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      ctx.options |= OpenSSL::SSL::OP_NO_TICKET\n    end\n\n    connections = nil\n    saved_session = nil\n    server_proc = Proc.new do |ctx, ssl|\n      stats = ctx.session_cache_stats\n\n      case connections\n      when 0\n        assert_equal false, ssl.session_reused?\n        assert_equal 1, stats[:cache_num]\n        assert_equal 0, stats[:cache_hits]\n        assert_equal 0, stats[:cache_misses]\n      when 1\n        assert_equal true, ssl.session_reused?\n        assert_equal 1, stats[:cache_num]\n        assert_equal 1, stats[:cache_hits]\n        assert_equal 0, stats[:cache_misses]\n\n        saved_session = ssl.session\n        assert_equal true, ctx.session_remove(ssl.session)\n      when 2\n        assert_equal false, ssl.session_reused?\n        assert_equal 1, stats[:cache_num]\n        assert_equal 1, stats[:cache_hits]\n        assert_equal 1, stats[:cache_misses]\n\n        assert_equal true, ctx.session_add(saved_session.dup)\n      when 3\n        assert_equal true, ssl.session_reused?\n        assert_equal 2, stats[:cache_num]\n        assert_equal 2, stats[:cache_hits]\n        assert_equal 1, stats[:cache_misses]\n\n        ctx.flush_sessions(Time.now + 10000)\n      when 4\n        assert_equal false, ssl.session_reused?\n        assert_equal 1, stats[:cache_num]\n        assert_equal 2, stats[:cache_hits]\n        assert_equal 2, stats[:cache_misses]\n\n        assert_equal true, ctx.session_add(saved_session.dup)\n      end\n\n      readwrite_loop(ctx, ssl)\n    end\n\n    start_server(ctx_proc: ctx_proc, server_proc: server_proc) do |port|\n      first_session = nil\n      10.times do |i|\n        connections = i\n        cctx = OpenSSL::SSL::SSLContext.new\n        cctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n        server_connect_with_session(port, cctx, first_session) { |ssl|\n          ssl.puts(\"abc\"); assert_equal \"abc\\n\", ssl.gets\n          first_session ||= ssl.session\n\n          case connections\n          when 0;\n          when 1; assert_equal true, ssl.session_reused?\n          when 2; assert_equal false, ssl.session_reused?\n          when 3; assert_equal true, ssl.session_reused?\n          when 4; assert_equal false, ssl.session_reused?\n          when 5..9; assert_equal true, ssl.session_reused?\n          end\n        }\n      end\n    end\n  end\n\n  # Skipping tests that use session_remove_cb by default because it may cause\n  # deadlock.\n  TEST_SESSION_REMOVE_CB = ENV[\"OSSL_TEST_UNSAFE\"] == \"1\"\n\n  def test_ctx_client_session_cb_tls12\n    start_server do |port|\n      called = {}\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.min_version = ctx.max_version = :TLS1_2\n      ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT\n      ctx.session_new_cb = lambda { |ary|\n        sock, sess = ary\n        called[:new] = [sock, sess]\n      }\n      if TEST_SESSION_REMOVE_CB\n        ctx.session_remove_cb = lambda { |ary|\n          ctx, sess = ary\n          called[:remove] = [ctx, sess]\n        }\n      end\n\n      server_connect_with_session(port, ctx, nil) { |ssl|\n        assert_equal(1, ctx.session_cache_stats[:connect_good])\n        assert_equal([ssl, ssl.session], called[:new])\n        # AWS-LC doesn't support internal session caching on the client, but\n        # the callback is still enabled as expected.\n        unless aws_lc?\n          assert_equal(1, ctx.session_cache_stats[:cache_num])\n          assert_equal(true, ctx.session_remove(ssl.session))\n          if TEST_SESSION_REMOVE_CB\n            assert_equal([ctx, ssl.session], called[:remove])\n          end\n        end\n        assert_equal(false, ctx.session_remove(ssl.session))\n      }\n    end\n  end\n\n  def test_ctx_client_session_cb_tls13\n    omit \"LibreSSL does not call session_new_cb in TLS 1.3\" if libressl?\n    omit \"AWS-LC does not support internal session caching on the client\" if aws_lc?\n\n    start_server do |port|\n      called = {}\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.min_version = :TLS1_3\n      ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT\n      ctx.session_new_cb = lambda { |ary|\n        sock, sess = ary\n        called[:new] = [sock, sess]\n      }\n\n      server_connect_with_session(port, ctx, nil) { |ssl|\n        ssl.puts(\"abc\"); assert_equal(\"abc\\n\", ssl.gets)\n\n        assert_operator(1, :<=, ctx.session_cache_stats[:cache_num])\n        assert_operator(1, :<=, ctx.session_cache_stats[:connect_good])\n        assert_equal([ssl, ssl.session], called[:new])\n      }\n    end\n  end\n\n  def test_ctx_client_session_cb_tls13_exception\n    omit \"LibreSSL does not call session_new_cb in TLS 1.3\" if libressl?\n\n    server_proc = lambda do |ctx, ssl|\n      readwrite_loop(ctx, ssl)\n    rescue SystemCallError, OpenSSL::SSL::SSLError\n    end\n    start_server(server_proc: server_proc) do |port|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.min_version = :TLS1_3\n      ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT\n      ctx.session_new_cb = lambda { |ary|\n        raise \"in session_new_cb\"\n      }\n\n      server_connect_with_session(port, ctx, nil) { |ssl|\n        assert_raise_with_message(RuntimeError, /in session_new_cb/) {\n          ssl.puts(\"abc\"); assert_equal(\"abc\\n\", ssl.gets)\n        }\n      }\n    end\n  end\n\n  def test_ctx_server_session_cb\n    connections = nil\n    called = {}\n    cctx = OpenSSL::SSL::SSLContext.new\n    cctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n    sctx = nil\n    ctx_proc = Proc.new { |ctx|\n      sctx = ctx\n      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION\n      ctx.options |= OpenSSL::SSL::OP_NO_TICKET\n\n      # get_cb is called whenever a client proposed to resume a session but\n      # the session could not be found in the internal session cache.\n      last_server_session = nil\n      ctx.session_get_cb = lambda { |ary|\n        _sess, data = ary\n        called[:get] = data\n\n        if connections == 2\n          last_server_session.dup\n        else\n          nil\n        end\n      }\n\n      ctx.session_new_cb = lambda { |ary|\n        _sock, sess = ary\n        called[:new] = sess\n        last_server_session = sess\n      }\n\n      if TEST_SESSION_REMOVE_CB\n        ctx.session_remove_cb = lambda { |ary|\n          _ctx, sess = ary\n          called[:remove] = sess\n        }\n      end\n    }\n    start_server(ctx_proc: ctx_proc) do |port|\n      connections = 0\n      sess0 = server_connect_with_session(port, cctx, nil) { |ssl|\n        ssl.puts(\"abc\"); assert_equal \"abc\\n\", ssl.gets\n        assert_equal false, ssl.session_reused?\n        ssl.session\n      }\n      assert_nil called[:get]\n      assert_not_nil called[:new]\n      assert_equal sess0.id, called[:new].id\n      if TEST_SESSION_REMOVE_CB\n        assert_nil called[:remove]\n      end\n      called.clear\n\n      # Internal cache hit\n      connections = 1\n      server_connect_with_session(port, cctx, sess0.dup) { |ssl|\n        ssl.puts(\"abc\"); assert_equal \"abc\\n\", ssl.gets\n        assert_equal true, ssl.session_reused?\n        ssl.session\n      }\n      assert_nil called[:get]\n      assert_nil called[:new]\n      if TEST_SESSION_REMOVE_CB\n        assert_nil called[:remove]\n      end\n      called.clear\n\n      sctx.flush_sessions(Time.now + 10000)\n      if TEST_SESSION_REMOVE_CB\n        assert_not_nil called[:remove]\n        assert_equal sess0.id, called[:remove].id\n      end\n      called.clear\n\n      # External cache hit\n      connections = 2\n      sess2 = server_connect_with_session(port, cctx, sess0.dup) { |ssl|\n        ssl.puts(\"abc\"); assert_equal \"abc\\n\", ssl.gets\n        assert_equal true, ssl.session_reused?\n        ssl.session\n      }\n      assert_equal sess0.id, sess2.id\n      assert_equal sess0.id, called[:get]\n      assert_nil called[:new]\n      if TEST_SESSION_REMOVE_CB\n        assert_nil called[:remove]\n      end\n      called.clear\n\n      sctx.flush_sessions(Time.now + 10000)\n      if TEST_SESSION_REMOVE_CB\n        assert_not_nil called[:remove]\n        assert_equal sess0.id, called[:remove].id\n      end\n      called.clear\n\n      # Cache miss\n      connections = 3\n      sess3 = server_connect_with_session(port, cctx, sess0.dup) { |ssl|\n        ssl.puts(\"abc\"); assert_equal \"abc\\n\", ssl.gets\n        assert_equal false, ssl.session_reused?\n        ssl.session\n      }\n      assert_not_equal sess0.id, sess3.id\n      assert_equal sess0.id, called[:get]\n      assert_not_nil called[:new]\n      assert_equal sess3.id, called[:new].id\n      if TEST_SESSION_REMOVE_CB\n        assert_nil called[:remove]\n      end\n    end\n  end\n\n  def test_dup\n    sess_orig = OpenSSL::SSL::Session.new(DUMMY_SESSION)\n    sess_dup = sess_orig.dup\n    assert_equal(sess_orig.to_der, sess_dup.to_der)\n  end\n\n  private\n\n  def server_connect_with_session(port, ctx = nil, sess = nil)\n    sock = TCPSocket.new(\"127.0.0.1\", port)\n    ctx ||= OpenSSL::SSL::SSLContext.new\n    ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)\n    ssl.session = sess if sess\n    ssl.sync_close = true\n    ssl.connect\n    yield ssl if block_given?\n  ensure\n    ssl&.close\n    sock&.close\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_ts.rb",
    "content": "require_relative \"utils\"\n\nif defined?(OpenSSL) && defined?(OpenSSL::Timestamp)\n\nclass OpenSSL::TestTimestamp < OpenSSL::TestCase\n  def intermediate_key\n    @intermediate_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_\n-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQCcyODxH+oTrr7l7MITWcGaYnnBma6vidCCJjuSzZpaRmXZHAyH\n0YcY4ttC0BdJ4uV+cE05IySVC7tyvVfFb8gFQ6XJV+AEktP+XkLbcxZgj9d2NVu1\nziXdI+ldXkPnMhyWpMS5E7SD6gflv9NhUYEsmAGsUgdK6LDmm2W2/4TlewIDAQAB\nAoGAYgx6KDFWONLqjW3f/Sv/mGYHUNykUyDzpcD1Npyf797gqMMSzwlo3FZa2tC6\nD7n23XirwpTItvEsW9gvgMikJDPlThAeGLZ+L0UbVNNBHVxGP998Nda1kxqKvhRE\npfZCKc7PLM9ZXc6jBTmgxdcAYfVCCVUoa2mEf9Ktr3BlI4kCQQDQAM09+wHDXGKP\no2UnCwCazGtyGU2r0QCzHlh9BVY+KD2KjjhuWh86rEbdWN7hEW23Je1vXIhuM6Pa\n/Ccd+XYnAkEAwPZ91PK6idEONeGQ4I3dyMKV2SbaUjfq3MDL4iIQPQPuj7QsBO/5\n3Nf9ReSUUTRFCUVwoC8k4Z1KAJhR/K/ejQJANE7PTnPuGJQGETs09+GTcFpR9uqY\nFspDk8fg1ufdrVnvSAXF+TJewiGK3KU5v33jinhWQngRsyz3Wt2odKhEZwJACbjh\noicQqvzzgFd7GzVKpWDYd/ZzLY1PsgusuhoJQ2m9TVRAm4cTycLAKhNYPbcqe0sa\nX5fAffWU0u7ZwqeByQJAOUAbYET4RU3iymAvAIDFj8LiQnizG9t5Ty3HXlijKQYv\ny8gsvWd4CdxwOPatWpBUX9L7IXcMJmD44xXTUvpbfQ==\n-----END RSA PRIVATE KEY-----\n_end_of_pem_\n  end\n\n  def ee_key\n    @ee_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_\n-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQDA6eB5r2O5KOKNbKMBhzadl43lgpwqq28m+G0gH38kKCL1f3o9\nP8xUZm7sZqcWEervZMSSXMGBV9DgeoSR+U6FMJywgQGx/JNRx7wZTMNym3PvgLkl\nxCXh6ZA0/xbtJtcNI+UUv0ENBkTIuUWBhkAf3jQclAr9aQ0ktYBuHAcRcQIDAQAB\nAoGAKNhcAuezwZx6e18pFEXAtpVEIfgJgK9TlXi8AjUpAkrNPBWFmDpN1QDrM3p4\nnh+lEpLPW/3vqqchPqYyM4YJraMLpS3KUG+s7+m9QIia0ri2WV5Cig7WL+Tl9p7K\nb3oi2Aj/wti8GfOLFQXOQQ4Ea4GoCv2Sxe0GZR39UBxzTsECQQD1zuVIwBvqU2YR\n8innsoa+j4u2hulRmQO6Zgpzj5vyRYfA9uZxQ9nKbfJvzuWwUv+UzyS9RqxarqrP\n5nQw5EmVAkEAyOmJg6+AfGrgvSWfSpXEds/WA/sHziCO3rE4/sd6cnDc6XcTgeMs\nmT8Z3kAYGpqFDew5orUylPfJJa+PUueJbQJAY+gkvw3+Cp69FLw1lgu0wo07fwOU\nn2qu3jsNMm0DOFRUWfTAMvcd9S385L7WEnWZldUfnKK1+OGXYYrMXPbchQJAChU2\nUoaHQzc16iguM1cK0g+iJPb/MEgQA3sPajHmokGpxIm2T+lvvo0dJjs/Om6QyN8X\nEWRYkoNQ8/Q4lCeMjQJAfvDIGtyqF4PieFHYgluQAv5pGgYpakdc8SYyeRH9NKey\nGaL27FRs4fRWf9OmxPhUVgIyGzLGXrueemvQUDHObA==\n-----END RSA PRIVATE KEY-----\n_end_of_pem_\n  end\n\n  def ca_cert\n    @ca_cert ||= OpenSSL::Certs.ca_cert\n  end\n\n  def ca_store\n    @ca_store ||= OpenSSL::X509::Store.new.tap { |s| s.add_cert(ca_cert) }\n  end\n\n  def ts_cert_direct\n    @ts_cert_direct ||= OpenSSL::Certs.ts_cert_direct(ee_key, ca_cert)\n  end\n\n  def intermediate_cert\n    @intermediate_cert ||= OpenSSL::Certs.intermediate_cert(intermediate_key, ca_cert)\n  end\n\n  def intermediate_store\n    @intermediate_store ||= OpenSSL::X509::Store.new.tap { |s| s.add_cert(intermediate_cert) }\n  end\n\n  def ts_cert_ee\n    @ts_cert_ee ||= OpenSSL::Certs.ts_cert_ee(ee_key, intermediate_cert, intermediate_key)\n  end\n\n  def test_request_mandatory_fields\n    req = OpenSSL::Timestamp::Request.new\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      req.to_der\n    end\n    req.algorithm = \"sha1\"\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      req.to_der\n    end\n    req.message_imprint = OpenSSL::Digest.digest('SHA1', \"data\")\n    assert_nothing_raised { req.to_der }\n  end\n\n  def test_request_assignment\n    req = OpenSSL::Timestamp::Request.new\n\n    req.version = 2\n    assert_equal(2, req.version)\n    assert_raise(TypeError) { req.version = nil }\n    assert_raise(TypeError) { req.version = \"foo\" }\n\n    req.algorithm = \"sha1\"\n    assert_equal(\"SHA1\", req.algorithm)\n    assert_equal(\"SHA1\", OpenSSL::ASN1.ObjectId(\"SHA1\").sn)\n    assert_raise(TypeError) { req.algorithm = nil }\n    assert_raise(OpenSSL::ASN1::ASN1Error) { req.algorithm = \"xxx\" }\n\n    req.message_imprint = \"test\"\n    assert_equal(\"test\", req.message_imprint)\n    assert_raise(TypeError) { req.message_imprint = nil }\n\n    req.policy_id = \"1.2.3.4.5\"\n    assert_equal(\"1.2.3.4.5\", req.policy_id)\n    assert_raise(TypeError) { req.policy_id = 123 }\n    assert_raise(TypeError) { req.policy_id = nil }\n\n    req.nonce = 42\n    assert_equal(42, req.nonce)\n    assert_raise(TypeError) { req.nonce = \"foo\" }\n    assert_raise(TypeError) { req.nonce = nil }\n\n    req.cert_requested = false\n    assert_equal(false, req.cert_requested?)\n    req.cert_requested = nil\n    assert_equal(false, req.cert_requested?)\n    req.cert_requested = 123\n    assert_equal(true, req.cert_requested?)\n    req.cert_requested = \"asdf\"\n    assert_equal(true, req.cert_requested?)\n  end\n\n  def test_request_serialization\n    req = OpenSSL::Timestamp::Request.new\n\n    req.version = 2\n    req.algorithm = \"SHA1\"\n    req.message_imprint = \"test\"\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n    req.cert_requested = true\n\n    req = OpenSSL::Timestamp::Request.new(req.to_der)\n\n    assert_equal(2, req.version)\n    assert_equal(\"SHA1\", req.algorithm)\n    assert_equal(\"test\", req.message_imprint)\n    assert_equal(\"1.2.3.4.5\", req.policy_id)\n    assert_equal(42, req.nonce)\n    assert_equal(true, req.cert_requested?)\n\n  end\n\n  def test_request_re_assignment\n    #tests whether the potential 'freeing' of previous values in C works properly\n    req = OpenSSL::Timestamp::Request.new\n    req.version = 2\n    req.version = 3\n    req.algorithm = \"SHA1\"\n    req.algorithm = \"SHA256\"\n    req.message_imprint = \"test\"\n    req.message_imprint = \"test2\"\n    req.policy_id = \"1.2.3.4.5\"\n    req.policy_id = \"1.2.3.4.6\"\n    req.nonce = 42\n    req.nonce = 24\n    req.cert_requested = false\n    req.cert_requested = true\n    req.to_der\n  end\n\n  def test_request_encode_decode\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n\n    qer = OpenSSL::Timestamp::Request.new(req.to_der)\n    assert_equal(1, qer.version)\n    assert_equal(\"SHA1\", qer.algorithm)\n    assert_equal(digest, qer.message_imprint)\n    assert_equal(\"1.2.3.4.5\", qer.policy_id)\n    assert_equal(42, qer.nonce)\n\n    #put OpenSSL::ASN1.decode inbetween\n    qer2 = OpenSSL::Timestamp::Request.new(OpenSSL::ASN1.decode(req.to_der))\n    assert_equal(1, qer2.version)\n    assert_equal(\"SHA1\", qer2.algorithm)\n    assert_equal(digest, qer2.message_imprint)\n    assert_equal(\"1.2.3.4.5\", qer2.policy_id)\n    assert_equal(42, qer2.nonce)\n  end\n\n  def test_request_invalid_asn1\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      OpenSSL::Timestamp::Request.new(\"*\" * 44)\n    end\n  end\n\n  def test_response_constants\n    assert_equal(0, OpenSSL::Timestamp::Response::GRANTED)\n    assert_equal(1, OpenSSL::Timestamp::Response::GRANTED_WITH_MODS)\n    assert_equal(2, OpenSSL::Timestamp::Response::REJECTION)\n    assert_equal(3, OpenSSL::Timestamp::Response::WAITING)\n    assert_equal(4, OpenSSL::Timestamp::Response::REVOCATION_WARNING)\n    assert_equal(5, OpenSSL::Timestamp::Response::REVOCATION_NOTIFICATION)\n  end\n\n  def test_response_creation\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n\n    fac = OpenSSL::Timestamp::Factory.new\n    time = Time.now\n    fac.gen_time = time\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    resp = OpenSSL::Timestamp::Response.new(resp)\n    assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status)\n    assert_nil(resp.failure_info)\n    assert_equal([], resp.status_text)\n    assert_equal(1, resp.token_info.version)\n    assert_equal(\"1.2.3.4.5\", resp.token_info.policy_id)\n    assert_equal(\"SHA1\", resp.token_info.algorithm)\n    assert_equal(digest, resp.token_info.message_imprint)\n    assert_equal(1, resp.token_info.serial_number)\n    assert_equal(time.to_i, resp.token_info.gen_time.to_i)\n    assert_equal(false, resp.token_info.ordering)\n    assert_nil(resp.token_info.nonce)\n    assert_cert(ts_cert_ee, resp.tsa_certificate)\n    #compare PKCS7\n    token = OpenSSL::ASN1.decode(resp.to_der).value[1]\n    assert_equal(token.to_der, resp.token.to_der)\n  end\n\n  def test_response_failure_info\n    resp = OpenSSL::Timestamp::Response.new(\"0\\\"0 \\x02\\x01\\x020\\x17\\f\\x15Invalid TimeStampReq.\\x03\\x02\\x06\\x80\")\n    assert_equal(:BAD_ALG, resp.failure_info)\n  end\n\n  def test_response_mandatory_fields\n    fac = OpenSSL::Timestamp::Factory.new\n    req = OpenSSL::Timestamp::Request.new\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      fac.create_timestamp(ee_key, ts_cert_ee, req)\n    end\n    req.algorithm = \"sha1\"\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      fac.create_timestamp(ee_key, ts_cert_ee, req)\n    end\n    req.message_imprint = OpenSSL::Digest.digest('SHA1', \"data\")\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      fac.create_timestamp(ee_key, ts_cert_ee, req)\n    end\n    fac.gen_time = Time.now\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      fac.create_timestamp(ee_key, ts_cert_ee, req)\n    end\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      fac.create_timestamp(ee_key, ts_cert_ee, req)\n    end\n    fac.default_policy_id = \"1.2.3.4.5\"\n    assert_equal OpenSSL::Timestamp::Response::GRANTED, fac.create_timestamp(ee_key, ts_cert_ee, req).status\n    fac.default_policy_id = nil\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      fac.create_timestamp(ee_key, ts_cert_ee, req)\n    end\n    req.policy_id = \"1.2.3.4.5\"\n    assert_equal OpenSSL::Timestamp::Response::GRANTED, fac.create_timestamp(ee_key, ts_cert_ee, req).status\n  end\n\n  def test_response_allowed_digests\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    req.message_imprint = OpenSSL::Digest.digest('SHA1', \"test\")\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.default_policy_id = \"1.2.3.4.6\"\n\n    # None allowed by default\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status\n\n    # Explicitly allow SHA1 (string)\n    fac.allowed_digests = [\"sha1\"]\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal OpenSSL::Timestamp::Response::GRANTED, resp.status\n\n    # Explicitly allow SHA1 (object)\n    fac.allowed_digests = [OpenSSL::Digest.new('SHA1')]\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal OpenSSL::Timestamp::Response::GRANTED, resp.status\n\n    # Others not allowed\n    req.algorithm = \"SHA256\"\n    req.message_imprint = OpenSSL::Digest.digest('SHA256', \"test\")\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status\n\n    # Non-Array\n    fac.allowed_digests = 123\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal OpenSSL::Timestamp::Response::REJECTION, resp.status\n\n    # Non-String, non-Digest Array element\n    fac.allowed_digests = [\"sha1\", OpenSSL::Digest.new('SHA1'), 123]\n    assert_raise(TypeError) do\n      fac.create_timestamp(ee_key, ts_cert_ee, req)\n    end\n  end\n\n  def test_response_default_policy\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    fac.default_policy_id = \"1.2.3.4.6\"\n\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status)\n    assert_equal(\"1.2.3.4.6\", resp.token_info.policy_id)\n\n    assert_match(/1\\.2\\.3\\.4\\.6/, resp.to_text)\n  end\n\n  def test_response_bad_purpose\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n\n\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      fac.create_timestamp(ee_key, intermediate_cert, req)\n    end\n  end\n\n  def test_response_invalid_asn1\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      OpenSSL::Timestamp::Response.new(\"*\" * 44)\n    end\n  end\n\n  def test_no_cert_requested\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.cert_requested = false\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    fac.default_policy_id = \"1.2.3.4.5\"\n\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal(OpenSSL::Timestamp::Response::GRANTED, resp.status)\n    assert_nil(resp.tsa_certificate)\n  end\n\n  def test_response_no_policy_defined\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      fac.create_timestamp(ee_key, ts_cert_ee, req)\n    end\n  end\n\n  def test_verify_ee_no_req\n    ts, _ = timestamp_ee\n    assert_raise(TypeError) do\n      ts.verify(nil, ca_cert)\n    end\n  end\n\n  def test_verify_ee_no_store\n    ts, req = timestamp_ee\n    assert_raise(TypeError) do\n      ts.verify(req, nil)\n    end\n  end\n\n  def test_verify_ee_wrong_root_no_intermediate\n    ts, req = timestamp_ee\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      ts.verify(req, intermediate_store)\n    end\n  end\n\n  def test_verify_ee_wrong_root_wrong_intermediate\n    ts, req = timestamp_ee\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      ts.verify(req, intermediate_store, [ca_cert])\n    end\n  end\n\n  def test_verify_ee_nonce_mismatch\n    ts, req = timestamp_ee\n    req.nonce = 1\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      ts.verify(req, ca_store, [intermediate_cert])\n    end\n  end\n\n  def test_verify_ee_intermediate_missing\n    ts, req = timestamp_ee\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      ts.verify(req, ca_store)\n    end\n  end\n\n  def test_verify_ee_intermediate\n    ts, req = timestamp_ee\n    ts.verify(req, ca_store, [intermediate_cert])\n  end\n\n  def test_verify_ee_intermediate_type_error\n    ts, req = timestamp_ee\n    assert_raise(TypeError) { ts.verify(req, [ca_cert], 123) }\n  end\n\n  def test_verify_ee_def_policy\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.nonce = 42\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    fac.default_policy_id = \"1.2.3.4.5\"\n\n    ts = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    ts.verify(req, ca_store, [intermediate_cert])\n  end\n\n  def test_verify_direct\n    ts, req = timestamp_direct\n    ts.verify(req, ca_store)\n  end\n\n  def test_verify_direct_redundant_untrusted\n    ts, req = timestamp_direct\n    ts.verify(req, ca_store, [ts.tsa_certificate, ts.tsa_certificate])\n  end\n\n  def test_verify_direct_unrelated_untrusted\n    ts, req = timestamp_direct\n    ts.verify(req, ca_store, [intermediate_cert])\n  end\n\n  def test_verify_direct_wrong_root\n    ts, req = timestamp_direct\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      ts.verify(req, intermediate_store)\n    end\n  end\n\n  def test_verify_direct_no_cert_no_intermediate\n    ts, req = timestamp_direct_no_cert\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      ts.verify(req, ca_store)\n    end\n  end\n\n  def test_verify_ee_no_cert\n    ts, req = timestamp_ee_no_cert\n    assert_same(ts, ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert]))\n  end\n\n  def test_verify_ee_no_cert_no_intermediate\n    ts, req = timestamp_ee_no_cert\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      ts.verify(req, ca_store, [ts_cert_ee])\n    end\n  end\n\n  def test_verify_ee_additional_certs_array\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    fac.additional_certs = [intermediate_cert]\n    ts = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal(2, ts.token.certificates.size)\n    fac.additional_certs = nil\n    ts.verify(req, ca_store)\n    ts = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal(1, ts.token.certificates.size)\n  end\n\n  def test_verify_ee_additional_certs_with_root\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    fac.additional_certs = [intermediate_cert, ca_cert]\n    ts = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_equal(3, ts.token.certificates.size)\n    ts.verify(req, ca_store)\n  end\n\n  def test_verify_ee_cert_inclusion_not_requested\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.nonce = 42\n    req.cert_requested = false\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    #needed because the Request contained no policy identifier\n    fac.default_policy_id = '1.2.3.4.5'\n    fac.additional_certs = [ ts_cert_ee, intermediate_cert ]\n    ts = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    assert_nil(ts.token.certificates) #since cert_requested? == false\n    ts.verify(req, ca_store, [ts_cert_ee, intermediate_cert])\n  end\n\n  def test_reusable\n    #test if req and faq are reusable, i.e. the internal\n    #CTX_free methods don't mess up e.g. the certificates\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    fac.additional_certs = [ intermediate_cert ]\n    ts1 = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    ts1.verify(req, ca_store)\n    ts2 = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    ts2.verify(req, ca_store)\n    refute_nil(ts1.tsa_certificate)\n    refute_nil(ts2.tsa_certificate)\n  end\n\n  def test_token_info_creation\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = OpenSSL::BN.new(123)\n\n    fac = OpenSSL::Timestamp::Factory.new\n    time = Time.now\n    fac.gen_time = time\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n\n    resp = fac.create_timestamp(ee_key, ts_cert_ee, req)\n    info = resp.token_info\n    info = OpenSSL::Timestamp::TokenInfo.new(info.to_der)\n\n    assert_equal(1, info.version)\n    assert_equal(\"1.2.3.4.5\", info.policy_id)\n    assert_equal(\"SHA1\", info.algorithm)\n    assert_equal(digest, info.message_imprint)\n    assert_equal(1, info.serial_number)\n    assert_equal(time.to_i, info.gen_time.to_i)\n    assert_equal(false, info.ordering)\n    assert_equal(123, info.nonce)\n  end\n\n  def test_token_info_invalid_asn1\n    assert_raise(OpenSSL::Timestamp::TimestampError) do\n      OpenSSL::Timestamp::TokenInfo.new(\"*\" * 44)\n    end\n  end\n\n  private\n\n  def assert_cert expected, actual\n    assert_equal expected.to_der, actual.to_der\n  end\n\n  def timestamp_ee\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    return fac.create_timestamp(ee_key, ts_cert_ee, req), req\n  end\n\n  def timestamp_ee_no_cert\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n    req.cert_requested = false\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    return fac.create_timestamp(ee_key, ts_cert_ee, req), req\n  end\n\n  def timestamp_direct\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    return fac.create_timestamp(ee_key, ts_cert_direct, req), req\n  end\n\n  def timestamp_direct_no_cert\n    req = OpenSSL::Timestamp::Request.new\n    req.algorithm = \"SHA1\"\n    digest = OpenSSL::Digest.digest('SHA1', \"test\")\n    req.message_imprint = digest\n    req.policy_id = \"1.2.3.4.5\"\n    req.nonce = 42\n    req.cert_requested = false\n\n    fac = OpenSSL::Timestamp::Factory.new\n    fac.gen_time = Time.now\n    fac.serial_number = 1\n    fac.allowed_digests = [\"sha1\"]\n    return fac.create_timestamp(ee_key, ts_cert_direct, req), req\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_x509attr.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestX509Attribute < OpenSSL::TestCase\n  def test_new\n    ef = OpenSSL::X509::ExtensionFactory.new\n    val = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([\n      ef.create_extension(\"keyUsage\", \"keyCertSign\", true)\n    ])])\n    attr = OpenSSL::X509::Attribute.new(\"extReq\", val)\n    assert_equal(\"extReq\", attr.oid)\n    assert_equal(val.to_der, attr.value.to_der)\n\n    attr = OpenSSL::X509::Attribute.new(\"1.2.840.113549.1.9.14\", val)\n    assert_equal(\"extReq\", attr.oid)\n  end\n\n  def test_from_der\n    # oid: challengePassword, values: Set[UTF8String<\"abc123\">]\n    test_der = \"\\x30\\x15\\x06\\x09\\x2a\\x86\\x48\\x86\\xf7\\x0d\\x01\\x09\\x07\\x31\\x08\" \\\n      \"\\x0c\\x06\\x61\\x62\\x63\\x31\\x32\\x33\".b\n    attr = OpenSSL::X509::Attribute.new(test_der)\n    assert_equal(test_der, attr.to_der)\n    assert_equal(\"challengePassword\", attr.oid)\n    assert_equal(\"abc123\", attr.value.value[0].value)\n  end\n\n  def test_to_der\n    ef = OpenSSL::X509::ExtensionFactory.new\n    val = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([\n      ef.create_extension(\"keyUsage\", \"keyCertSign\", true)\n    ])])\n    attr = OpenSSL::X509::Attribute.new(\"extReq\", val)\n    expected = OpenSSL::ASN1::Sequence.new([\n      OpenSSL::ASN1::ObjectId.new(\"extReq\"),\n      val\n    ])\n    assert_equal(expected.to_der, attr.to_der)\n  end\n\n  def test_invalid_value\n    # should not change the original value\n    test_der = \"\\x30\\x15\\x06\\x09\\x2a\\x86\\x48\\x86\\xf7\\x0d\\x01\\x09\\x07\\x31\\x08\" \\\n      \"\\x0c\\x06\\x61\\x62\\x63\\x31\\x32\\x33\".b\n    attr = OpenSSL::X509::Attribute.new(test_der)\n    assert_raise(TypeError) {\n      attr.value = \"1234\"\n    }\n    assert_raise(OpenSSL::X509::AttributeError) {\n      v = OpenSSL::ASN1::Set([OpenSSL::ASN1::UTF8String(\"1234\")], 17, :EXPLICIT)\n      attr.value = v\n    }\n    assert_equal(test_der, attr.to_der)\n    assert_raise(OpenSSL::X509::AttributeError) {\n      attr.oid = \"abc123\"\n    }\n    assert_equal(test_der, attr.to_der)\n  end\n\n  def test_dup\n    val = OpenSSL::ASN1::Set([\n      OpenSSL::ASN1::UTF8String(\"abc123\")\n    ])\n    attr = OpenSSL::X509::Attribute.new(\"challengePassword\", val)\n    assert_equal(attr.to_der, attr.dup.to_der)\n  end\n\n  def test_eq\n    val1 = OpenSSL::ASN1::Set([\n      OpenSSL::ASN1::UTF8String(\"abc123\")\n    ])\n    attr1 = OpenSSL::X509::Attribute.new(\"challengePassword\", val1)\n    attr2 = OpenSSL::X509::Attribute.new(\"challengePassword\", val1)\n    ef = OpenSSL::X509::ExtensionFactory.new\n    val2 = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([\n      ef.create_extension(\"keyUsage\", \"keyCertSign\", true)\n    ])])\n    attr3 = OpenSSL::X509::Attribute.new(\"extReq\", val2)\n\n    assert_equal false, attr1 == 12345\n    assert_equal true, attr1 == attr2\n    assert_equal false, attr1 == attr3\n  end\n\n  def test_marshal\n    val = OpenSSL::ASN1::Set([\n      OpenSSL::ASN1::UTF8String(\"abc123\")\n    ])\n    attr = OpenSSL::X509::Attribute.new(\"challengePassword\", val)\n    deserialized = Marshal.load(Marshal.dump(attr))\n\n    assert_equal attr.to_der, deserialized.to_der\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_x509cert.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestX509Certificate < OpenSSL::TestCase\n  def setup\n    super\n    @rsa1 = Fixtures.pkey(\"rsa-1\")\n    @rsa2 = Fixtures.pkey(\"rsa-2\")\n    @ec1 = Fixtures.pkey(\"p256\")\n    @ca = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=CA\")\n    @ee1 = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=EE1\")\n  end\n\n  def test_serial\n    [1, 2**32, 2**100].each{|s|\n      cert = issue_cert(@ca, @rsa1, s, [], nil, nil)\n      assert_equal(s, cert.serial)\n      cert = OpenSSL::X509::Certificate.new(cert.to_der)\n      assert_equal(s, cert.serial)\n    }\n  end\n\n  def test_public_key\n    exts = [\n      [\"basicConstraints\",\"CA:TRUE\",true],\n      [\"subjectKeyIdentifier\",\"hash\",false],\n      [\"authorityKeyIdentifier\",\"keyid:always\",false],\n    ]\n    cert = issue_cert(@ca, @rsa1, 1, exts, nil, nil)\n    assert_kind_of(OpenSSL::PKey::RSA, cert.public_key)\n    assert_equal(@rsa1.public_to_der, cert.public_key.public_to_der)\n    cert = OpenSSL::X509::Certificate.new(cert.to_der)\n    assert_equal(@rsa1.public_to_der, cert.public_key.public_to_der)\n  end\n\n  def test_validity\n    now = Time.at(Time.now.to_i + 0.9)\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil,\n                      not_before: now, not_after: now+3600)\n    assert_equal(Time.at(now.to_i), cert.not_before)\n    assert_equal(Time.at(now.to_i+3600), cert.not_after)\n\n    now = Time.at(now.to_i)\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil,\n                      not_before: now, not_after: now+3600)\n    assert_equal(now.getutc, cert.not_before)\n    assert_equal((now+3600).getutc, cert.not_after)\n\n    now = Time.at(0)\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil,\n                      not_before: now, not_after: now)\n    assert_equal(now.getutc, cert.not_before)\n    assert_equal(now.getutc, cert.not_after)\n\n    now = Time.at(0x7fffffff)\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil,\n                      not_before: now, not_after: now)\n    assert_equal(now.getutc, cert.not_before)\n    assert_equal(now.getutc, cert.not_after)\n  end\n\n  def test_extension_factory\n    ca_exts = [\n      [\"basicConstraints\",\"CA:TRUE\",true],\n      [\"keyUsage\",\"keyCertSign, cRLSign\",true],\n      [\"subjectKeyIdentifier\",\"hash\",false],\n      [\"authorityKeyIdentifier\",\"issuer:always,keyid:always\",false],\n    ]\n    ca_cert = issue_cert(@ca, @rsa1, 1, ca_exts, nil, nil)\n    ca_cert.extensions.each_with_index{|ext, i|\n      assert_equal(ca_exts[i].first, ext.oid)\n      assert_equal(ca_exts[i].last, ext.critical?)\n    }\n\n    ee1_exts = [\n      [\"keyUsage\",\"Non Repudiation, Digital Signature, Key Encipherment\",true],\n      [\"subjectKeyIdentifier\",\"hash\",false],\n      [\"authorityKeyIdentifier\",\"issuer:always,keyid:always\",false],\n      [\"extendedKeyUsage\",\"clientAuth, emailProtection, codeSigning\",false],\n      [\"subjectAltName\",\"email:ee1@ruby-lang.org\",false],\n    ]\n    ee1_cert = issue_cert(@ee1, @rsa2, 2, ee1_exts, ca_cert, @rsa1)\n    assert_equal(ca_cert.subject.to_der, ee1_cert.issuer.to_der)\n    ee1_cert.extensions.each_with_index{|ext, i|\n      assert_equal(ee1_exts[i].first, ext.oid)\n      assert_equal(ee1_exts[i].last, ext.critical?)\n    }\n  end\n\n  def test_akiski\n    ca_cert = generate_cert(@ca, @rsa1, 4, nil)\n    ef = OpenSSL::X509::ExtensionFactory.new(ca_cert, ca_cert)\n    ca_cert.add_extension(\n      ef.create_extension(\"subjectKeyIdentifier\", \"hash\", false))\n    ca_cert.add_extension(\n      ef.create_extension(\"authorityKeyIdentifier\", \"issuer:always,keyid:always\", false))\n    ca_cert.sign(@rsa1, \"sha256\")\n\n    ca_keyid = get_subject_key_id(ca_cert.to_der, hex: false)\n    assert_equal ca_keyid, ca_cert.authority_key_identifier\n    assert_equal ca_keyid, ca_cert.subject_key_identifier\n\n    ee_cert = generate_cert(@ee1, @rsa2, 5, ca_cert)\n    ef = OpenSSL::X509::ExtensionFactory.new(ca_cert, ee_cert)\n    ee_cert.add_extension(\n      ef.create_extension(\"subjectKeyIdentifier\", \"hash\", false))\n    ee_cert.add_extension(\n      ef.create_extension(\"authorityKeyIdentifier\", \"issuer:always,keyid:always\", false))\n    ee_cert.sign(@rsa1, \"sha256\")\n\n    ee_keyid = get_subject_key_id(ee_cert.to_der, hex: false)\n    assert_equal ca_keyid, ee_cert.authority_key_identifier\n    assert_equal ee_keyid, ee_cert.subject_key_identifier\n  end\n\n  def test_akiski_missing\n    cert = issue_cert(@ee1, @rsa1, 1, [], nil, nil)\n    assert_nil(cert.authority_key_identifier)\n    assert_nil(cert.subject_key_identifier)\n  end\n\n  def test_crl_uris_no_crl_distribution_points\n    cert = issue_cert(@ee1, @rsa1, 1, [], nil, nil)\n    assert_nil(cert.crl_uris)\n  end\n\n  def test_crl_uris\n    # Multiple DistributionPoint contains a single general name each\n    ef = OpenSSL::X509::ExtensionFactory.new\n    ef.config = OpenSSL::Config.parse(<<~_cnf_)\n      [crlDistPts]\n      URI.1 = http://www.example.com/crl\n      URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary\n    _cnf_\n    cdp_cert = generate_cert(@ee1, @rsa1, 3, nil)\n    ef.subject_certificate = cdp_cert\n    cdp_cert.add_extension(ef.create_extension(\"crlDistributionPoints\", \"@crlDistPts\"))\n    cdp_cert.sign(@rsa1, \"sha256\")\n    assert_equal(\n      [\"http://www.example.com/crl\", \"ldap://ldap.example.com/cn=ca?certificateRevocationList;binary\"],\n      cdp_cert.crl_uris\n    )\n  end\n\n  def test_crl_uris_multiple_general_names\n    # Single DistributionPoint contains multiple general names of type URI\n    ef = OpenSSL::X509::ExtensionFactory.new\n    ef.config = OpenSSL::Config.parse(<<~_cnf_)\n      [crlDistPts_section]\n      fullname = URI:http://www.example.com/crl, URI:ldap://ldap.example.com/cn=ca?certificateRevocationList;binary\n    _cnf_\n    cdp_cert = generate_cert(@ee1, @rsa1, 3, nil)\n    ef.subject_certificate = cdp_cert\n    cdp_cert.add_extension(ef.create_extension(\"crlDistributionPoints\", \"crlDistPts_section\"))\n    cdp_cert.sign(@rsa1, \"sha256\")\n    assert_equal(\n      [\"http://www.example.com/crl\", \"ldap://ldap.example.com/cn=ca?certificateRevocationList;binary\"],\n      cdp_cert.crl_uris\n    )\n  end\n\n  def test_crl_uris_no_uris\n    # The only DistributionPointName is a directoryName\n    ef = OpenSSL::X509::ExtensionFactory.new\n    ef.config = OpenSSL::Config.parse(<<~_cnf_)\n      [crlDistPts_section]\n      fullname = dirName:dirname_section\n      [dirname_section]\n      CN = dirname\n    _cnf_\n    cdp_cert = generate_cert(@ee1, @rsa1, 3, nil)\n    ef.subject_certificate = cdp_cert\n    cdp_cert.add_extension(ef.create_extension(\"crlDistributionPoints\", \"crlDistPts_section\"))\n    cdp_cert.sign(@rsa1, \"sha256\")\n    assert_nil(cdp_cert.crl_uris)\n  end\n\n  def test_aia_missing\n    cert = issue_cert(@ee1, @rsa1, 1, [], nil, nil)\n    assert_nil(cert.ca_issuer_uris)\n    assert_nil(cert.ocsp_uris)\n  end\n\n  def test_aia\n    ef = OpenSSL::X509::ExtensionFactory.new\n    aia_cert = generate_cert(@ee1, @rsa1, 4, nil)\n    ef.subject_certificate = aia_cert\n    aia_cert.add_extension(\n      ef.create_extension(\n        \"authorityInfoAccess\",\n        \"caIssuers;URI:http://www.example.com/caIssuers,\" \\\n        \"caIssuers;URI:ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary,\" \\\n        \"OCSP;URI:http://www.example.com/ocsp,\" \\\n        \"OCSP;URI:ldap://ldap.example.com/cn=ca?authorityInfoAccessOcsp;binary\",\n        false\n      )\n    )\n    aia_cert.sign(@rsa1, \"sha256\")\n    assert_equal(\n      [\"http://www.example.com/caIssuers\", \"ldap://ldap.example.com/cn=ca?authorityInfoAccessCaIssuers;binary\"],\n      aia_cert.ca_issuer_uris\n    )\n    assert_equal(\n      [\"http://www.example.com/ocsp\", \"ldap://ldap.example.com/cn=ca?authorityInfoAccessOcsp;binary\"],\n      aia_cert.ocsp_uris\n    )\n  end\n\n  def test_invalid_extension\n    integer = OpenSSL::ASN1::Integer.new(0)\n    invalid_exts_cert = generate_cert(@ee1, @rsa1, 1, nil)\n    [\"subjectKeyIdentifier\", \"authorityKeyIdentifier\", \"crlDistributionPoints\", \"authorityInfoAccess\"].each do |ext|\n      invalid_exts_cert.add_extension(\n        OpenSSL::X509::Extension.new(ext, integer.to_der)\n      )\n    end\n\n    assert_raise(OpenSSL::ASN1::ASN1Error, \"invalid extension\") {\n      invalid_exts_cert.authority_key_identifier\n    }\n    assert_raise(OpenSSL::ASN1::ASN1Error, \"invalid extension\") {\n      invalid_exts_cert.subject_key_identifier\n    }\n    assert_raise(OpenSSL::ASN1::ASN1Error, \"invalid extension\") {\n      invalid_exts_cert.crl_uris\n    }\n    assert_raise(OpenSSL::ASN1::ASN1Error, \"invalid extension\") {\n      invalid_exts_cert.ca_issuer_uris\n    }\n    assert_raise(OpenSSL::ASN1::ASN1Error, \"invalid extension\") {\n      invalid_exts_cert.ocsp_uris\n    }\n  end\n\n  def test_sign_and_verify\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil, digest: \"SHA256\")\n    assert_equal(\"sha256WithRSAEncryption\", cert.signature_algorithm) # ln\n    assert_equal(true, cert.verify(@rsa1))\n    assert_equal(false, cert.verify(@rsa2))\n    assert_equal(false, certificate_error_returns_false { cert.verify(@ec1) })\n    cert.serial = 2\n    assert_equal(false, cert.verify(@rsa1))\n  end\n\n  def test_sign_and_verify_nil_digest\n    # Ed25519 is not FIPS-approved.\n    omit_on_fips\n    ed25519 = OpenSSL::PKey::generate_key(\"ED25519\")\n    cert = issue_cert(@ca, ed25519, 1, [], nil, nil, digest: nil)\n    assert_equal(true, cert.verify(ed25519))\n  end\n\n  def test_check_private_key\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    assert_equal(true, cert.check_private_key(@rsa1))\n  end\n\n  def test_read_from_file\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    Tempfile.create(\"cert\") { |f|\n      f << cert.to_pem\n      f.rewind\n      assert_equal cert.to_der, OpenSSL::X509::Certificate.new(f).to_der\n    }\n  end\n\n  def test_read_der_then_pem\n    cert1 = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    exts = [\n      # A new line before PEM block\n      [\"nsComment\", \"Another certificate:\\n\" + cert1.to_pem],\n    ]\n    cert2 = issue_cert(@ca, @rsa1, 2, exts, nil, nil)\n\n    assert_equal cert2, OpenSSL::X509::Certificate.new(cert2.to_der)\n    assert_equal cert2, OpenSSL::X509::Certificate.new(cert2.to_pem)\n  end\n\n  def test_eq\n    now = Time.now\n    cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil,\n                        not_before: now, not_after: now + 3600)\n    cert1 = issue_cert(@ee1, @rsa2, 2, [], cacert, @rsa1,\n                       not_before: now, not_after: now + 3600)\n    cert2 = issue_cert(@ee1, @rsa2, 2, [], cacert, @rsa1,\n                       not_before: now, not_after: now + 3600)\n    cert3 = issue_cert(@ee1, @rsa2, 3, [], cacert, @rsa1,\n                       not_before: now, not_after: now + 3600)\n    cert4 = issue_cert(@ee1, @rsa2, 2, [], cacert, @rsa1,\n                       digest: \"sha512\", not_before: now, not_after: now + 3600)\n\n    assert_equal false, cert1 == 12345\n    assert_equal true, cert1 == cert2\n    assert_equal false, cert1 == cert3\n    assert_equal false, cert1 == cert4\n    assert_equal false, cert3 == cert4\n  end\n\n  def test_inspect\n    cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    assert_include(cacert.inspect, \"subject=#{@ca.inspect}\")\n\n    # Do not raise an exception for an invalid certificate\n    assert_instance_of(String, OpenSSL::X509::Certificate.new.inspect)\n  end\n\n  def test_marshal\n    now = Time.now\n    cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil,\n      not_before: now, not_after: now + 3600)\n    cert = issue_cert(@ee1, @rsa2, 2, [], cacert, @rsa1,\n      not_before: now, not_after: now + 3600)\n    deserialized = Marshal.load(Marshal.dump(cert))\n\n    assert_equal cert.to_der, deserialized.to_der\n  end\n\n  def test_load_file_empty_pem\n    Tempfile.create(\"empty.pem\") do |f|\n      f.close\n\n      assert_raise(OpenSSL::X509::CertificateError) do\n        OpenSSL::X509::Certificate.load_file(f.path)\n      end\n    end\n  end\n\n  def test_load_file_fullchain_pem\n    cert1 = issue_cert(@ee1, @rsa1, 1, [], nil, nil)\n    cert2 = issue_cert(@ca, @rsa2, 1, [], nil, nil)\n\n    Tempfile.create(\"fullchain.pem\") do |f|\n      f.puts cert1.to_pem\n      f.puts cert2.to_pem\n      f.close\n\n      certificates = OpenSSL::X509::Certificate.load_file(f.path)\n      assert_equal 2, certificates.size\n      assert_equal @ee1, certificates[0].subject\n      assert_equal @ca, certificates[1].subject\n    end\n  end\n\n  def test_load_file_certificate_der\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    Tempfile.create(\"certificate.der\", binmode: true) do |f|\n      f.write cert.to_der\n      f.close\n\n      certificates = OpenSSL::X509::Certificate.load_file(f.path)\n\n      # DER encoding can only contain one certificate:\n      assert_equal 1, certificates.size\n      assert_equal cert.to_der, certificates[0].to_der\n    end\n  end\n\n  def test_load_file_fullchain_garbage\n    Tempfile.create(\"garbage.txt\") do |f|\n      f.puts \"not a certificate\"\n      f.close\n\n      assert_raise(OpenSSL::X509::CertificateError) do\n        OpenSSL::X509::Certificate.load_file(f.path)\n      end\n    end\n  end\n\n  def test_tbs_precert_bytes\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    seq = OpenSSL::ASN1.decode(cert.tbs_bytes)\n\n    assert_equal 7, seq.value.size\n  end\n\n  private\n\n  def certificate_error_returns_false\n    yield\n  rescue OpenSSL::X509::CertificateError\n    false\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_x509crl.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestX509CRL < OpenSSL::TestCase\n  def setup\n    super\n    @rsa1 = Fixtures.pkey(\"rsa-1\")\n    @rsa2 = Fixtures.pkey(\"rsa-2\")\n    @ca = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=CA\")\n  end\n\n  def test_basic\n    now = Time.at(Time.now.to_i)\n\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    crl = issue_crl([], 1, now, now+1600, [], cert, @rsa1, \"SHA256\")\n    assert_equal(1, crl.version)\n    assert_equal(cert.issuer.to_der, crl.issuer.to_der)\n    assert_equal(now, crl.last_update)\n    assert_equal(now+1600, crl.next_update)\n    assert_equal(\"sha256WithRSAEncryption\", crl.signature_algorithm) # ln\n\n    crl = OpenSSL::X509::CRL.new(crl.to_der)\n    assert_equal(1, crl.version)\n    assert_equal(cert.issuer.to_der, crl.issuer.to_der)\n    assert_equal(now, crl.last_update)\n    assert_equal(now+1600, crl.next_update)\n  end\n\n  def test_revoked\n\n    # CRLReason ::= ENUMERATED {\n    #      unspecified             (0),\n    #      keyCompromise           (1),\n    #      cACompromise            (2),\n    #      affiliationChanged      (3),\n    #      superseded              (4),\n    #      cessationOfOperation    (5),\n    #      certificateHold         (6),\n    #      removeFromCRL           (8),\n    #      privilegeWithdrawn      (9),\n    #      aACompromise           (10) }\n\n    now = Time.at(Time.now.to_i)\n    revoke_info = [\n      [1, Time.at(0),          1],\n      [2, Time.at(0x7fffffff), 2],\n      [3, now,                 3],\n      [4, now,                 4],\n      [5, now,                 5],\n    ]\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [],\n                    cert, @rsa1, \"SHA256\")\n    revoked = crl.revoked\n    assert_equal(5, revoked.size)\n    assert_equal(1, revoked[0].serial)\n    assert_equal(2, revoked[1].serial)\n    assert_equal(3, revoked[2].serial)\n    assert_equal(4, revoked[3].serial)\n    assert_equal(5, revoked[4].serial)\n\n    assert_equal(Time.at(0), revoked[0].time)\n    assert_equal(Time.at(0x7fffffff), revoked[1].time)\n    assert_equal(now, revoked[2].time)\n    assert_equal(now, revoked[3].time)\n    assert_equal(now, revoked[4].time)\n\n    assert_equal(\"CRLReason\", revoked[0].extensions[0].oid)\n    assert_equal(\"CRLReason\", revoked[1].extensions[0].oid)\n    assert_equal(\"CRLReason\", revoked[2].extensions[0].oid)\n    assert_equal(\"CRLReason\", revoked[3].extensions[0].oid)\n    assert_equal(\"CRLReason\", revoked[4].extensions[0].oid)\n\n    assert_equal(\"Key Compromise\", revoked[0].extensions[0].value)\n    assert_equal(\"CA Compromise\", revoked[1].extensions[0].value)\n    assert_equal(\"Affiliation Changed\", revoked[2].extensions[0].value)\n    assert_equal(\"Superseded\", revoked[3].extensions[0].value)\n    assert_equal(\"Cessation Of Operation\", revoked[4].extensions[0].value)\n\n    assert_equal(false, revoked[0].extensions[0].critical?)\n    assert_equal(false, revoked[1].extensions[0].critical?)\n    assert_equal(false, revoked[2].extensions[0].critical?)\n    assert_equal(false, revoked[3].extensions[0].critical?)\n    assert_equal(false, revoked[4].extensions[0].critical?)\n\n    assert_equal(\"Key Compromise\", revoked[0].extensions[0].value)\n    assert_equal(\"CA Compromise\", revoked[1].extensions[0].value)\n    assert_equal(\"Affiliation Changed\", revoked[2].extensions[0].value)\n    assert_equal(\"Superseded\", revoked[3].extensions[0].value)\n    assert_equal(\"Cessation Of Operation\", revoked[4].extensions[0].value)\n\n    revoke_info = (1..1000).collect{|i| [i, now, 0] }\n    crl = issue_crl(revoke_info, 1, Time.now, Time.now+1600, [],\n                    cert, @rsa1, \"SHA256\")\n    revoked = crl.revoked\n    assert_equal(1000, revoked.size)\n    assert_equal(1, revoked[0].serial)\n    assert_equal(1000, revoked[999].serial)\n\n    crl.revoked = revoked\n    revoked2 = crl.revoked\n    assert_equal(revoked.map(&:serial), revoked2.map(&:serial))\n  end\n\n  def test_extension\n    cert_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"subjectKeyIdentifier\", \"hash\", false],\n      [\"authorityKeyIdentifier\", \"keyid:always\", false],\n      [\"subjectAltName\", \"email:xyzzy@ruby-lang.org\", false],\n      [\"keyUsage\", \"cRLSign, keyCertSign\", true],\n    ]\n    crl_exts = [\n      [\"authorityKeyIdentifier\", \"issuer:always,keyid:always\", false],\n      [\"issuerAltName\", \"issuer:copy\", false],\n    ]\n\n    cert = issue_cert(@ca, @rsa1, 1, cert_exts, nil, nil)\n    crl = issue_crl([], 1, Time.now, Time.now+1600, crl_exts,\n                    cert, @rsa1, \"SHA256\")\n    exts = crl.extensions\n    assert_equal(3, exts.size)\n    assert_equal(\"1\", exts[0].value)\n    assert_equal(\"crlNumber\", exts[0].oid)\n    assert_equal(false, exts[0].critical?)\n\n    expected_keyid = OpenSSL::TestUtils.get_subject_key_id(cert, hex: false)\n    assert_equal expected_keyid, crl.authority_key_identifier\n\n    assert_equal(\"authorityKeyIdentifier\", exts[1].oid)\n    keyid = OpenSSL::TestUtils.get_subject_key_id(cert)\n    assert_match(/^keyid:#{keyid}/, exts[1].value)\n    assert_equal(false, exts[1].critical?)\n\n    assert_equal(\"issuerAltName\", exts[2].oid)\n    assert_equal(\"email:xyzzy@ruby-lang.org\", exts[2].value)\n    assert_equal(false, exts[2].critical?)\n\n    crl = OpenSSL::X509::CRL.new(crl.to_der)\n    exts = crl.extensions\n    assert_equal(3, exts.size)\n    assert_equal(\"1\", exts[0].value)\n    assert_equal(\"crlNumber\", exts[0].oid)\n    assert_equal(false, exts[0].critical?)\n\n    assert_equal(\"authorityKeyIdentifier\", exts[1].oid)\n    keyid = OpenSSL::TestUtils.get_subject_key_id(cert)\n    assert_match(/^keyid:#{keyid}/, exts[1].value)\n    assert_equal(false, exts[1].critical?)\n\n    assert_equal(\"issuerAltName\", exts[2].oid)\n    assert_equal(\"email:xyzzy@ruby-lang.org\", exts[2].value)\n    assert_equal(false, exts[2].critical?)\n\n    no_ext_crl = issue_crl([], 1, Time.now, Time.now+1600, [],\n                           cert, @rsa1, \"SHA256\")\n    assert_equal nil, no_ext_crl.authority_key_identifier\n  end\n\n  def test_crlnumber\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, @rsa1, \"SHA256\")\n    assert_match(1.to_s, crl.extensions[0].value)\n    assert_match(/X509v3 CRL Number:\\s+#{1}/m, crl.to_text)\n\n    crl = issue_crl([], 2**32, Time.now, Time.now+1600, [],\n                    cert, @rsa1, \"SHA256\")\n    assert_match((2**32).to_s, crl.extensions[0].value)\n    assert_match(/X509v3 CRL Number:\\s+#{2**32}/m, crl.to_text)\n\n    crl = issue_crl([], 2**100, Time.now, Time.now+1600, [],\n                    cert, @rsa1, \"SHA256\")\n    assert_match(/X509v3 CRL Number:\\s+#{2**100}/m, crl.to_text)\n    assert_match((2**100).to_s, crl.extensions[0].value)\n  end\n\n  def test_sign_and_verify\n    p256 = Fixtures.pkey(\"p256\")\n\n    cert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, @rsa1, \"SHA256\")\n    assert_equal(true, crl.verify(@rsa1))\n    assert_equal(false, crl.verify(@rsa2))\n    assert_equal(false, crl_error_returns_false { crl.verify(p256) })\n    crl.version = 0\n    assert_equal(false, crl.verify(@rsa1))\n\n    cert = issue_cert(@ca, p256, 1, [], nil, nil)\n    crl = issue_crl([], 1, Time.now, Time.now+1600, [], cert, p256, \"SHA256\")\n    assert_equal(false, crl_error_returns_false { crl.verify(@rsa1) })\n    assert_equal(false, crl_error_returns_false { crl.verify(@rsa2) })\n    assert_equal(true, crl.verify(p256))\n    crl.version = 0\n    assert_equal(false, crl.verify(p256))\n  end\n\n  def test_sign_and_verify_nil_digest\n    # Ed25519 is not FIPS-approved.\n    omit_on_fips\n    ed25519 = OpenSSL::PKey::generate_key(\"ED25519\")\n    cert = issue_cert(@ca, ed25519, 1, [], nil, nil, digest: nil)\n    crl = issue_crl([], 1, Time.now, Time.now+1600, [],\n                    cert, ed25519, nil)\n    assert_equal(false, crl_error_returns_false { crl.verify(@rsa1) })\n    assert_equal(false, crl.verify(OpenSSL::PKey::generate_key(\"ED25519\")))\n    assert_equal(true,  crl.verify(ed25519))\n    crl.version = 0\n    assert_equal(false, crl.verify(ed25519))\n  end\n\n  def test_revoked_to_der\n    # revokedCertificates     SEQUENCE OF SEQUENCE  {\n    #      userCertificate         CertificateSerialNumber,\n    #      revocationDate          Time,\n    #      crlEntryExtensions      Extensions OPTIONAL\n    #                               -- if present, version MUST be v2\n    #                           }  OPTIONAL,\n\n    now = Time.utc(2000, 1, 1)\n    rev1 = OpenSSL::X509::Revoked.new\n    rev1.serial = 123\n    rev1.time = now\n    ext = OpenSSL::X509::Extension.new(\"CRLReason\", OpenSSL::ASN1::Enumerated(1))\n    rev1.extensions = [ext]\n    asn1 = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Integer(123),\n      OpenSSL::ASN1::UTCTime(now),\n      OpenSSL::ASN1::Sequence([ext.to_der])\n    ])\n\n    assert_equal asn1.to_der, rev1.to_der\n  end\n\n  def test_eq\n    now = Time.now\n\n    cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    crl1 = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1, \"SHA256\")\n    rev1 = OpenSSL::X509::Revoked.new.tap { |rev|\n      rev.serial = 1\n      rev.time = now\n    }\n    crl1.add_revoked(rev1)\n    crl2 = OpenSSL::X509::CRL.new(crl1.to_der)\n\n    # CRL\n    assert_equal false, crl1 == 12345\n    assert_equal true, crl1 == crl2\n    rev2 = OpenSSL::X509::Revoked.new.tap { |rev|\n      rev.serial = 2\n      rev.time = now\n    }\n    crl2.add_revoked(rev2)\n    assert_equal false, crl1 == crl2\n\n    # Revoked\n    assert_equal false, rev1 == 12345\n    assert_equal true, rev1 == crl2.revoked[0]\n    assert_equal false, rev1 == crl2.revoked[1]\n    assert_equal true, rev2 == crl2.revoked[1]\n  end\n\n  def test_marshal\n    now = Time.now\n\n    cacert = issue_cert(@ca, @rsa1, 1, [], nil, nil)\n    crl = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1, \"SHA256\")\n    rev = OpenSSL::X509::Revoked.new.tap { |rev|\n      rev.serial = 1\n      rev.time = now\n    }\n    crl.add_revoked(rev)\n    deserialized = Marshal.load(Marshal.dump(crl))\n\n    assert_equal crl.to_der, deserialized.to_der\n    assert_equal crl.revoked[0].to_der, deserialized.revoked[0].to_der\n  end\n\n  private\n\n  def crl_error_returns_false\n    yield\n  rescue OpenSSL::X509::CRLError\n    false\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_x509ext.rb",
    "content": "# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestX509Extension < OpenSSL::TestCase\n  def setup\n    super\n    @basic_constraints_value = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::Boolean(true),   # CA\n      OpenSSL::ASN1::Integer(2)       # pathlen\n    ])\n    @basic_constraints = OpenSSL::ASN1::Sequence([\n      OpenSSL::ASN1::ObjectId(\"basicConstraints\"),\n      OpenSSL::ASN1::Boolean(true),\n      OpenSSL::ASN1::OctetString(@basic_constraints_value.to_der),\n    ])\n  end\n\n  def test_new\n    ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der)\n    assert_equal(\"basicConstraints\", ext.oid)\n    assert_equal(true, ext.critical?)\n    assert_equal(\"CA:TRUE, pathlen:2\", ext.value)\n\n    ext = OpenSSL::X509::Extension.new(\"2.5.29.19\",\n                                       @basic_constraints_value.to_der, true)\n    assert_equal(@basic_constraints.to_der, ext.to_der)\n  end\n\n  def test_create_by_factory\n    ef = OpenSSL::X509::ExtensionFactory.new\n\n    bc = ef.create_extension(\"basicConstraints\", \"critical, CA:TRUE, pathlen:2\")\n    assert_equal(@basic_constraints.to_der, bc.to_der)\n\n    bc = ef.create_extension(\"basicConstraints\", \"CA:TRUE, pathlen:2\", true)\n    assert_equal(@basic_constraints.to_der, bc.to_der)\n\n    ef.config = OpenSSL::Config.parse(<<-_end_of_cnf_)\n    [crlDistPts]\n    URI.1 = http://www.example.com/crl\n    URI.2 = ldap://ldap.example.com/cn=ca?certificateRevocationList;binary\n\n    [certPolicies]\n    policyIdentifier = 2.23.140.1.2.1\n    CPS.1 = http://cps.example.com\n    _end_of_cnf_\n\n    cdp = ef.create_extension(\"crlDistributionPoints\", \"@crlDistPts\")\n    assert_equal(false, cdp.critical?)\n    assert_equal(\"crlDistributionPoints\", cdp.oid)\n    assert_include(cdp.value, \"URI:http://www.example.com/crl\")\n    assert_include(cdp.value,\n      \"URI:ldap://ldap.example.com/cn=ca?certificateRevocationList;binary\")\n\n    cdp = ef.create_extension(\"crlDistributionPoints\", \"critical, @crlDistPts\")\n    assert_equal(true, cdp.critical?)\n    assert_equal(\"crlDistributionPoints\", cdp.oid)\n    assert_include(cdp.value, \"URI:http://www.example.com/crl\")\n    assert_include(cdp.value,\n      \"URI:ldap://ldap.example.com/cn=ca?certificateRevocationList;binary\")\n\n    cp = ef.create_extension(\"certificatePolicies\", \"@certPolicies\")\n    assert_equal(false, cp.critical?)\n    assert_equal(\"certificatePolicies\", cp.oid)\n    assert_include(cp.value, \"2.23.140.1.2.1\")\n    assert_include(cp.value, \"http://cps.example.com\")\n  end\n\n  def test_factory_create_extension_sn_ln\n    ef = OpenSSL::X509::ExtensionFactory.new\n    bc_sn = ef.create_extension(\"basicConstraints\", \"critical, CA:TRUE, pathlen:2\")\n    bc_ln = ef.create_extension(\"X509v3 Basic Constraints\", \"critical, CA:TRUE, pathlen:2\")\n    assert_equal(@basic_constraints.to_der, bc_sn.to_der)\n    assert_equal(@basic_constraints.to_der, bc_ln.to_der)\n  end\n\n  def test_factory_create_extension_oid\n    ef = OpenSSL::X509::ExtensionFactory.new\n    ef.config = OpenSSL::Config.parse(<<~_end_of_cnf_)\n      [basic_constraints]\n      cA = BOOLEAN:TRUE\n      pathLenConstraint = INTEGER:2\n    _end_of_cnf_\n    bc_oid = ef.create_extension(\"2.5.29.19\", \"ASN1:SEQUENCE:basic_constraints\", true)\n    assert_equal(@basic_constraints.to_der, bc_oid.to_der)\n  end\n\n  def test_dup\n    ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der)\n    assert_equal(@basic_constraints.to_der, ext.to_der)\n    assert_equal(ext.to_der, ext.dup.to_der)\n  end\n\n  def test_eq\n    ext1 = OpenSSL::X509::Extension.new(@basic_constraints.to_der)\n    ef = OpenSSL::X509::ExtensionFactory.new\n    ext2 = ef.create_extension(\"basicConstraints\", \"critical, CA:TRUE, pathlen:2\")\n    ext3 = ef.create_extension(\"basicConstraints\", \"critical, CA:TRUE\")\n\n    assert_equal false, ext1 == 12345\n    assert_equal true, ext1 == ext2\n    assert_equal false, ext1 == ext3\n  end\n\n  def test_marshal\n    ef = OpenSSL::X509::ExtensionFactory.new\n    ext = ef.create_extension(\"basicConstraints\", \"critical, CA:TRUE, pathlen:2\")\n    deserialized = Marshal.load(Marshal.dump(ext))\n\n    assert_equal ext.to_der, deserialized.to_der\n  end\n\n  def test_value_der\n    ext = OpenSSL::X509::Extension.new(@basic_constraints.to_der)\n    assert_equal @basic_constraints_value.to_der, ext.value_der\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_x509name.rb",
    "content": "# coding: ASCII-8BIT\n# frozen_string_literal: true\nrequire_relative 'utils'\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestX509Name < OpenSSL::TestCase\n  def setup\n    super\n    @obj_type_tmpl = Hash.new(OpenSSL::ASN1::PRINTABLESTRING)\n    @obj_type_tmpl.update(OpenSSL::X509::Name::OBJECT_TYPE_TEMPLATE)\n  end\n\n  def test_s_new\n    dn = [ [\"C\", \"JP\"], [\"O\", \"example\"], [\"CN\", \"www.example.jp\"] ]\n    name = OpenSSL::X509::Name.new(dn)\n    ary = name.to_a\n    assert_equal(\"/C=JP/O=example/CN=www.example.jp\", name.to_s)\n    assert_equal(\"C\", ary[0][0])\n    assert_equal(\"O\", ary[1][0])\n    assert_equal(\"CN\", ary[2][0])\n    assert_equal(\"JP\", ary[0][1])\n    assert_equal(\"example\", ary[1][1])\n    assert_equal(\"www.example.jp\", ary[2][1])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2])\n    assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2])\n    assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2])\n\n    dn = [\n      [\"countryName\", \"JP\"],\n      [\"organizationName\", \"example\"],\n      [\"commonName\", \"www.example.jp\"]\n    ]\n    name = OpenSSL::X509::Name.new(dn)\n    ary = name.to_a\n    assert_equal(\"/C=JP/O=example/CN=www.example.jp\", name.to_s)\n    assert_equal(\"C\", ary[0][0])\n    assert_equal(\"O\", ary[1][0])\n    assert_equal(\"CN\", ary[2][0])\n    assert_equal(\"JP\", ary[0][1])\n    assert_equal(\"example\", ary[1][1])\n    assert_equal(\"www.example.jp\", ary[2][1])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2])\n    assert_equal(OpenSSL::ASN1::UTF8STRING, ary[1][2])\n    assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2])\n\n    name = OpenSSL::X509::Name.new(dn, @obj_type_tmpl)\n    ary = name.to_a\n    assert_equal(\"/C=JP/O=example/CN=www.example.jp\", name.to_s)\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2])\n\n    dn = [\n      [\"countryName\", \"JP\", OpenSSL::ASN1::PRINTABLESTRING],\n      [\"organizationName\", \"example\", OpenSSL::ASN1::PRINTABLESTRING],\n      [\"commonName\", \"www.example.jp\", OpenSSL::ASN1::PRINTABLESTRING]\n    ]\n    name = OpenSSL::X509::Name.new(dn)\n    ary = name.to_a\n    assert_equal(\"/C=JP/O=example/CN=www.example.jp\", name.to_s)\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[0][2])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[1][2])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2])\n\n    dn = [\n      [\"DC\", \"org\"],\n      [\"DC\", \"ruby-lang\"],\n      [\"CN\", \"GOTOU Yuuzou\"],\n      [\"emailAddress\", \"gotoyuzo@ruby-lang.org\"],\n      [\"serialNumber\", \"123\"],\n    ]\n    name = OpenSSL::X509::Name.new(dn)\n    ary = name.to_a\n    assert_equal(\"/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123\", name.to_s)\n    assert_equal(\"DC\", ary[0][0])\n    assert_equal(\"DC\", ary[1][0])\n    assert_equal(\"CN\", ary[2][0])\n    assert_equal(\"emailAddress\", ary[3][0])\n    assert_equal(\"serialNumber\", ary[4][0])\n    assert_equal(\"org\", ary[0][1])\n    assert_equal(\"ruby-lang\", ary[1][1])\n    assert_equal(\"GOTOU Yuuzou\", ary[2][1])\n    assert_equal(\"gotoyuzo@ruby-lang.org\", ary[3][1])\n    assert_equal(\"123\", ary[4][1])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2])\n    assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2])\n\n    name_from_der = OpenSSL::X509::Name.new(name.to_der)\n    assert_equal(name_from_der.to_s, name.to_s)\n    assert_equal(name_from_der.to_a, name.to_a)\n    assert_equal(name_from_der.to_der, name.to_der)\n  end\n\n  def test_unrecognized_oid\n    dn = [ [\"1.2.3.4.5.6.7.8.9.7.5.3.1\", \"Unknown OID 1\"],\n           [\"1.1.2.3.5.8.13.21.34\", \"Unknown OID 2\"],\n           [\"C\", \"US\"],\n           [\"postalCode\", \"60602\"],\n           [\"ST\", \"Illinois\"],\n           [\"L\", \"Chicago\"],\n           #[\"street\", \"123 Fake St\"],\n           [\"O\", \"Some Company LLC\"],\n           [\"CN\", \"mydomain.com\"] ]\n\n    name = OpenSSL::X509::Name.new(dn)\n    ary = name.to_a\n    #assert_equal(\"/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/street=123 Fake St/O=Some Company LLC/CN=mydomain.com\", name.to_s)\n    assert_equal(\"/1.2.3.4.5.6.7.8.9.7.5.3.1=Unknown OID 1/1.1.2.3.5.8.13.21.34=Unknown OID 2/C=US/postalCode=60602/ST=Illinois/L=Chicago/O=Some Company LLC/CN=mydomain.com\", name.to_s)\n    assert_equal(\"1.2.3.4.5.6.7.8.9.7.5.3.1\", ary[0][0])\n    assert_equal(\"1.1.2.3.5.8.13.21.34\", ary[1][0])\n    assert_equal(\"C\", ary[2][0])\n    assert_equal(\"postalCode\", ary[3][0])\n    assert_equal(\"ST\", ary[4][0])\n    assert_equal(\"L\", ary[5][0])\n    #assert_equal(\"street\", ary[6][0])\n    assert_equal(\"O\", ary[6][0])\n    assert_equal(\"CN\", ary[7][0])\n    assert_equal(\"Unknown OID 1\", ary[0][1])\n    assert_equal(\"Unknown OID 2\", ary[1][1])\n    assert_equal(\"US\", ary[2][1])\n    assert_equal(\"60602\", ary[3][1])\n    assert_equal(\"Illinois\", ary[4][1])\n    assert_equal(\"Chicago\", ary[5][1])\n    #assert_equal(\"123 Fake St\", ary[6][1])\n    assert_equal(\"Some Company LLC\", ary[6][1])\n    assert_equal(\"mydomain.com\", ary[7][1])\n  end\n\n  def test_unrecognized_oid_parse_encode_equality\n    dn = [ [\"1.2.3.4.5.6.7.8.9.7.5.3.2\", \"Unknown OID1\"],\n           [\"1.1.2.3.5.8.13.21.35\", \"Unknown OID2\"],\n           [\"C\", \"US\"],\n           [\"postalCode\", \"60602\"],\n           [\"ST\", \"Illinois\"],\n           [\"L\", \"Chicago\"],\n           #[\"street\", \"123 Fake St\"],\n           [\"O\", \"Some Company LLC\"],\n           [\"CN\", \"mydomain.com\"] ]\n\n    name1 = OpenSSL::X509::Name.new(dn)\n    name2 = OpenSSL::X509::Name.parse(name1.to_s)\n    assert_equal(name1.to_s, name2.to_s)\n    assert_equal(name1.to_a, name2.to_a)\n  end\n\n  def test_s_parse\n    dn = \"/DC=org/DC=ruby-lang/CN=www.ruby-lang.org/1.2.3.4.5.6=A=BCD\"\n    name = OpenSSL::X509::Name.parse(dn)\n    assert_equal(dn, name.to_s)\n    ary = name.to_a\n    assert_equal [\n      [\"DC\", \"org\", OpenSSL::ASN1::IA5STRING],\n      [\"DC\", \"ruby-lang\", OpenSSL::ASN1::IA5STRING],\n      [\"CN\", \"www.ruby-lang.org\", OpenSSL::ASN1::UTF8STRING],\n      [\"1.2.3.4.5.6\", \"A=BCD\", OpenSSL::ASN1::UTF8STRING],\n    ], ary\n\n    dn2 = \"DC=org, DC=ruby-lang, CN=www.ruby-lang.org, 1.2.3.4.5.6=A=BCD\"\n    name = OpenSSL::X509::Name.parse(dn2)\n    assert_equal(dn, name.to_s)\n    assert_equal ary, name.to_a\n\n    name = OpenSSL::X509::Name.parse(dn2, @obj_type_tmpl)\n    ary = name.to_a\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[3][2])\n  end\n\n  def test_s_parse_rfc2253\n    scanner = OpenSSL::X509::Name::RFC2253DN.method(:scan)\n\n    assert_equal([[\"C\", \"JP\"]], scanner.call(\"C=JP\"))\n    assert_equal([\n        [\"DC\", \"org\"],\n        [\"DC\", \"ruby-lang\"],\n        [\"CN\", \"GOTOU Yuuzou\"],\n        [\"emailAddress\", \"gotoyuzo@ruby-lang.org\"],\n      ],\n      scanner.call(\n        \"emailAddress=gotoyuzo@ruby-lang.org,CN=GOTOU Yuuzou,\"+\n        \"DC=ruby-lang,DC=org\")\n    )\n\n    u8 = OpenSSL::ASN1::UTF8STRING\n    assert_equal([\n        [\"DC\", \"org\"],\n        [\"DC\", \"ruby-lang\"],\n        [\"O\", \",=+<>#;\"],\n        [\"O\", \",=+<>#;\"],\n        [\"OU\", \"\"],\n        [\"OU\", \"\"],\n        [\"L\", \"aaa=\\\"bbb, ccc\\\"\"],\n        [\"L\", \"aaa=\\\"bbb, ccc\\\"\"],\n        [\"CN\", \"\\345\\276\\214\\350\\227\\244\\350\\243\\225\\350\\224\\265\"],\n        [\"CN\", \"\\345\\276\\214\\350\\227\\244\\350\\243\\225\\350\\224\\265\"],\n        [\"CN\", \"\\345\\276\\214\\350\\227\\244\\350\\243\\225\\350\\224\\265\"],\n        [\"CN\", \"\\345\\276\\214\\350\\227\\244\\350\\243\\225\\350\\224\\265\", u8],\n        [\"2.5.4.3\", \"GOTOU, Yuuzou\"],\n        [\"2.5.4.3\", \"GOTOU, Yuuzou\"],\n        [\"2.5.4.3\", \"GOTOU, Yuuzou\"],\n        [\"2.5.4.3\", \"GOTOU, Yuuzou\"],\n        [\"CN\", \"GOTOU \\\"gotoyuzo\\\" Yuuzou\"],\n        [\"CN\", \"GOTOU \\\"gotoyuzo\\\" Yuuzou\"],\n        [\"1.2.840.113549.1.9.1\", \"gotoyuzo@ruby-lang.org\"],\n        [\"emailAddress\", \"gotoyuzo@ruby-lang.org\"],\n      ],\n      scanner.call(\n        \"emailAddress=gotoyuzo@ruby-lang.org,\" +\n        \"1.2.840.113549.1.9.1=gotoyuzo@ruby-lang.org,\" +\n        'CN=GOTOU \\\"gotoyuzo\\\" Yuuzou,' +\n        'CN=\"GOTOU \\\"gotoyuzo\\\" Yuuzou\",' +\n        '2.5.4.3=GOTOU\\,\\20Yuuzou,' +\n        '2.5.4.3=GOTOU\\, Yuuzou,' +\n        '2.5.4.3=\"GOTOU, Yuuzou\",' +\n        '2.5.4.3=\"GOTOU\\, Yuuzou\",' +\n        \"CN=#0C0CE5BE8CE897A4E8A395E894B5,\" +\n        'CN=\\E5\\BE\\8C\\E8\\97\\A4\\E8\\A3\\95\\E8\\94\\B5,' +\n        \"CN=\\\"\\xE5\\xBE\\x8C\\xE8\\x97\\xA4\\xE8\\xA3\\x95\\xE8\\x94\\xB5\\\",\" +\n        \"CN=\\xE5\\xBE\\x8C\\xE8\\x97\\xA4\\xE8\\xA3\\x95\\xE8\\x94\\xB5,\" +\n        'L=aaa\\=\\\"bbb\\, ccc\\\",' +\n        'L=\"aaa=\\\"bbb, ccc\\\"\",' +\n        'OU=,' +\n        'OU=\"\",' +\n        'O=\\,\\=\\+\\<\\>\\#\\;,' +\n        'O=\",=+<>#;\",' +\n        \"DC=ruby-lang,\" +\n        \"DC=org\")\n    )\n\n    [\n      \"DC=org+DC=jp\",\n      \"DC=org,DC=ruby-lang+DC=rubyist,DC=www\"\n    ].each{|dn|\n      ex = scanner.call(dn) rescue $!\n      dn_r = Regexp.escape(dn)\n      assert_match(/^multi-valued RDN is not supported: #{dn_r}/, ex.message)\n    }\n\n    [\n      [\"DC=org,DC=exapmle,CN\", \"CN\"],\n      [\"DC=org,DC=example,\", \"\"],\n      [\"DC=org,DC=exapmle,CN=www.example.org;\", \"CN=www.example.org;\"],\n      [\"DC=org,DC=exapmle,CN=#www.example.org\", \"CN=#www.example.org\"],\n      [\"DC=org,DC=exapmle,CN=#777777.example.org\", \"CN=#777777.example.org\"],\n      [\"DC=org,DC=exapmle,CN=\\\"www.example\\\".org\", \"CN=\\\"www.example\\\".org\"],\n      [\"DC=org,DC=exapmle,CN=www.\\\"example.org\\\"\", \"CN=www.\\\"example.org\\\"\"],\n      [\"DC=org,DC=exapmle,CN=www.\\\"example\\\".org\", \"CN=www.\\\"example\\\".org\"],\n    ].each{|dn, msg|\n      ex = scanner.call(dn) rescue $!\n      assert_match(/^malformed RDN: .*=>#{Regexp.escape(msg)}/, ex.message)\n    }\n\n    dn = \"CN=www.ruby-lang.org,DC=ruby-lang,DC=org\"\n    name = OpenSSL::X509::Name.parse_rfc2253(dn)\n    assert_equal(dn, name.to_s(OpenSSL::X509::Name::RFC2253))\n    ary = name.to_a\n    assert_equal(\"DC\", ary[0][0])\n    assert_equal(\"DC\", ary[1][0])\n    assert_equal(\"CN\", ary[2][0])\n    assert_equal(\"org\", ary[0][1])\n    assert_equal(\"ruby-lang\", ary[1][1])\n    assert_equal(\"www.ruby-lang.org\", ary[2][1])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2])\n    assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2])\n  end\n\n  def test_add_entry\n    dn = [\n      [\"DC\", \"org\"],\n      [\"DC\", \"ruby-lang\"],\n      [\"CN\", \"GOTOU Yuuzou\"],\n      [\"emailAddress\", \"gotoyuzo@ruby-lang.org\"],\n      [\"serialNumber\", \"123\"],\n    ]\n    name = OpenSSL::X509::Name.new\n    dn.each{|attr| name.add_entry(*attr) }\n    ary = name.to_a\n    assert_equal(\"/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123\", name.to_s)\n    assert_equal(\"DC\", ary[0][0])\n    assert_equal(\"DC\", ary[1][0])\n    assert_equal(\"CN\", ary[2][0])\n    assert_equal(\"emailAddress\", ary[3][0])\n    assert_equal(\"serialNumber\", ary[4][0])\n    assert_equal(\"org\", ary[0][1])\n    assert_equal(\"ruby-lang\", ary[1][1])\n    assert_equal(\"GOTOU Yuuzou\", ary[2][1])\n    assert_equal(\"gotoyuzo@ruby-lang.org\", ary[3][1])\n    assert_equal(\"123\", ary[4][1])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2])\n    assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2])\n    assert_equal(OpenSSL::ASN1::IA5STRING, ary[3][2])\n    assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[4][2])\n  end\n\n  def test_add_entry_street\n    # openssl/crypto/objects/obj_mac.h 1.83\n    dn = [\n      [\"DC\", \"org\"],\n      [\"DC\", \"ruby-lang\"],\n      [\"CN\", \"GOTOU Yuuzou\"],\n      [\"emailAddress\", \"gotoyuzo@ruby-lang.org\"],\n      [\"serialNumber\", \"123\"],\n      [\"street\", \"Namiki\"],\n    ]\n    name = OpenSSL::X509::Name.new\n    dn.each{|attr| name.add_entry(*attr) }\n    ary = name.to_a\n    assert_equal(\"/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou/emailAddress=gotoyuzo@ruby-lang.org/serialNumber=123/street=Namiki\", name.to_s)\n    assert_equal(\"Namiki\", ary[5][1])\n  end\n\n  def test_add_entry_placing\n    der = %w{ 30 2A\n                 31 12\n                    30 10 06 03 55 04 0A 0C 09 72 75 62 79 2D 6C 61 6E 67\n                 31 14\n                    30 08 06 03 55 04 0B 0C 01 61\n                    30 08 06 03 55 04 0B 0C 01 62 }\n    orig = OpenSSL::X509::Name.new([der.join].pack(\"H*\"))\n    assert_equal(\"OU=b+OU=a,O=ruby-lang\", orig.to_s(OpenSSL::X509::Name::RFC2253))\n    # Skip for now; they do not work\n    #\n    # dn = orig.dup\n    # dn.add_entry(\"CN\", \"unya\", loc: 0, set: 0)\n    # assert_equal(\"OU=b+OU=a,O=ruby-lang,CN=unya\", dn.dup.to_s(OpenSSL::X509::Name::RFC2253))\n    # dn = orig.dup\n    # dn.add_entry(\"CN\", \"unya\", loc: 0, set: 1)\n    # assert_equal(\"OU=b+OU=a,O=ruby-lang+CN=unya\", dn.dup.to_s(OpenSSL::X509::Name::RFC2253))\n    dn = orig.dup\n    dn.add_entry(\"CN\", \"unya\", loc: 1, set: -1)\n    assert_equal(\"OU=b+OU=a,O=ruby-lang+CN=unya\", dn.dup.to_s(OpenSSL::X509::Name::RFC2253))\n    # dn = orig.dup\n    # dn.add_entry(\"CN\", \"unya\", loc: 1, set: 0)\n    # assert_equal(\"OU=b+OU=a,CN=unya,O=ruby-lang\", dn.dup.to_s(OpenSSL::X509::Name::RFC2253))\n    dn = orig.dup\n    dn.add_entry(\"CN\", \"unya\", loc: 1, set: 1)\n    assert_equal(\"CN=unya+OU=b+OU=a,O=ruby-lang\", dn.dup.to_s(OpenSSL::X509::Name::RFC2253))\n    dn = orig.dup\n    dn.add_entry(\"CN\", \"unya\", loc: -1, set: -1)\n    assert_equal(\"CN=unya+OU=b+OU=a,O=ruby-lang\", dn.dup.to_s(OpenSSL::X509::Name::RFC2253))\n    dn = orig.dup\n    dn.add_entry(\"CN\", \"unya\", loc: -1, set: 0)\n    assert_equal(\"CN=unya,OU=b+OU=a,O=ruby-lang\", dn.dup.to_s(OpenSSL::X509::Name::RFC2253))\n  end\n\n  def test_to_s\n    dn = [\n      [\"DC\", \"org\"],\n      [\"DC\", \"ruby-lang\"],\n      [\"CN\", \"フー, バー\"],\n    ]\n    name = OpenSSL::X509::Name.new\n    dn.each { |x| name.add_entry(*x) }\n\n    assert_equal \"/DC=org/DC=ruby-lang/\" \\\n      \"CN=\\\\xE3\\\\x83\\\\x95\\\\xE3\\\\x83\\\\xBC, \\\\xE3\\\\x83\\\\x90\\\\xE3\\\\x83\\\\xBC\",\n      name.to_s\n    # OpenSSL escapes characters with MSB by default\n    assert_equal \\\n      \"CN=\\\\E3\\\\83\\\\95\\\\E3\\\\83\\\\BC\\\\, \\\\E3\\\\83\\\\90\\\\E3\\\\83\\\\BC,\" \\\n      \"DC=ruby-lang,DC=org\",\n      name.to_s(OpenSSL::X509::Name::RFC2253)\n    assert_equal \"DC = org, DC = ruby-lang, \" \\\n      \"CN = \\\"\\\\E3\\\\83\\\\95\\\\E3\\\\83\\\\BC, \\\\E3\\\\83\\\\90\\\\E3\\\\83\\\\BC\\\"\",\n      name.to_s(OpenSSL::X509::Name::ONELINE)\n\n    empty = OpenSSL::X509::Name.new\n    assert_equal \"\", empty.to_s\n    assert_equal \"\", empty.to_s(OpenSSL::X509::Name::COMPAT)\n    assert_equal \"\", empty.to_s(OpenSSL::X509::Name::RFC2253)\n    assert_equal \"\", empty.to_s(OpenSSL::X509::Name::ONELINE)\n  end\n\n  def test_to_utf8\n    dn = [\n      [\"DC\", \"org\"],\n      [\"DC\", \"ruby-lang\"],\n      [\"CN\", \"フー, バー\"],\n    ]\n    name = OpenSSL::X509::Name.new\n    dn.each { |x| name.add_entry(*x) }\n\n    str = name.to_utf8\n    expected = String.new(\"CN=フー\\\\, バー,DC=ruby-lang,DC=org\").force_encoding(\"UTF-8\")\n    assert_equal expected, str\n    assert_equal Encoding.find(\"UTF-8\"), str.encoding\n\n    empty = OpenSSL::X509::Name.new\n    assert_equal \"\", empty.to_utf8\n  end\n\n  def test_equals2\n    n1 = OpenSSL::X509::Name.parse_rfc2253 'CN=a'\n    n2 = OpenSSL::X509::Name.parse_rfc2253 'CN=a'\n\n    assert_equal n1, n2\n\n    assert_equal(false, n1 == 'abc')\n    assert_equal(false, n2 == nil)\n  end\n\n  def test_spaceship\n    n1 = OpenSSL::X509::Name.new([[\"CN\", \"a\"]])\n    n2 = OpenSSL::X509::Name.new([[\"CN\", \"a\"]])\n    n3 = OpenSSL::X509::Name.new([[\"CN\", \"ab\"]])\n\n    assert_equal(0, n1 <=> n2)\n    assert_equal(-1, n1 <=> n3)\n    assert_equal(0, n2 <=> n1)\n    assert_equal(-1, n2 <=> n3)\n    assert_equal(1, n3 <=> n1)\n    assert_equal(1, n3 <=> n2)\n    assert_equal(nil, n1 <=> 'abc')\n    assert_equal(nil, n2 <=> 123)\n    assert_equal(nil, n3 <=> nil)\n  end\n\n  def test_hash_old\n    omit_on_fips # MD5\n\n    dn = \"/DC=org/DC=ruby-lang/CN=www.ruby-lang.org\"\n    name = OpenSSL::X509::Name.parse(dn)\n    d = OpenSSL::Digest.digest('MD5', name.to_der)\n    expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24\n    assert_equal(expected, name.hash_old)\n  end\n\n  def test_equality\n    name0 = OpenSSL::X509::Name.new([[\"DC\", \"org\"], [\"DC\", \"ruby-lang\"], [\"CN\", \"bar.ruby-lang.org\"]])\n    name1 = OpenSSL::X509::Name.new([[\"DC\", \"org\"], [\"DC\", \"ruby-lang\"], [\"CN\", \"bar.ruby-lang.org\"]])\n    name2 = OpenSSL::X509::Name.new([[\"DC\", \"org\"], [\"DC\", \"ruby-lang\"], [\"CN\", \"baz.ruby-lang.org\"]])\n    assert_equal true, name0 == name1\n    assert_equal true, name0.eql?(name1)\n    assert_equal false, name0 == name2\n    assert_equal false, name0.eql?(name2)\n  end\n\n  def test_marshal\n    name = OpenSSL::X509::Name.new([[\"DC\", \"org\"], [\"DC\", \"ruby-lang\"], [\"CN\", \"bar.ruby-lang.org\"]])\n    deserialized = Marshal.load(Marshal.dump(name))\n\n    assert_equal name.to_der, deserialized.to_der\n  end\n\n  def test_dup\n    name = OpenSSL::X509::Name.parse(\"/CN=ruby-lang.org\")\n    assert_equal(name.to_der, name.dup.to_der)\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_x509req.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestX509Request < OpenSSL::TestCase\n  def setup\n    super\n    @rsa1 = Fixtures.pkey(\"rsa-1\")\n    @rsa2 = Fixtures.pkey(\"rsa-2\")\n    @dn = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=GOTOU Yuuzou\")\n  end\n\n  def issue_csr(ver, dn, key, digest)\n    req = OpenSSL::X509::Request.new\n    req.version = ver\n    req.subject = dn\n    req.public_key = key\n    req.sign(key, digest)\n    req\n  end\n\n  def test_public_key\n    req = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    assert_kind_of(OpenSSL::PKey::RSA, req.public_key)\n    assert_equal(@rsa1.public_to_der, req.public_key.public_to_der)\n    req = OpenSSL::X509::Request.new(req.to_der)\n    assert_equal(@rsa1.public_to_der, req.public_key.public_to_der)\n  end\n\n  def test_version\n    req = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    assert_equal(0, req.version)\n    req = OpenSSL::X509::Request.new(req.to_der)\n    assert_equal(0, req.version)\n  end\n\n  def test_subject\n    req = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    assert_equal(@dn.to_der, req.subject.to_der)\n    req = OpenSSL::X509::Request.new(req.to_der)\n    assert_equal(@dn.to_der, req.subject.to_der)\n  end\n\n  def test_signature_algorithm\n    req = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    assert_equal(\"sha256WithRSAEncryption\", req.signature_algorithm) # ln\n  end\n\n  def create_ext_req(exts)\n    ef = OpenSSL::X509::ExtensionFactory.new\n    exts = exts.collect{|e| ef.create_extension(*e) }\n    return OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)])\n  end\n\n  def get_ext_req(ext_req_value)\n    set = OpenSSL::ASN1.decode(ext_req_value)\n    seq = set.value[0]\n    seq.value.collect{|asn1ext|\n      OpenSSL::X509::Extension.new(asn1ext).to_a\n    }\n  end\n\n  def test_attr\n    exts = [\n      [\"keyUsage\", \"Digital Signature, Key Encipherment\", true],\n      [\"subjectAltName\", \"email:gotoyuzo@ruby-lang.org\", false],\n    ]\n    attrval = create_ext_req(exts)\n    attrs = [\n      OpenSSL::X509::Attribute.new(\"extReq\", attrval),\n      OpenSSL::X509::Attribute.new(\"msExtReq\", attrval),\n    ]\n\n    req0 = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    attrs.each{|attr| req0.add_attribute(attr) }\n    req1 = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    req1.attributes = attrs\n    assert_equal(req0.to_der, req1.to_der)\n\n    attrs = req0.attributes\n    assert_equal(2, attrs.size)\n    assert_equal(\"extReq\", attrs[0].oid)\n    assert_equal(\"msExtReq\", attrs[1].oid)\n    assert_equal(exts, get_ext_req(attrs[0].value))\n    assert_equal(exts, get_ext_req(attrs[1].value))\n\n    req = OpenSSL::X509::Request.new(req0.to_der)\n    attrs = req.attributes\n    assert_equal(2, attrs.size)\n    assert_equal(\"extReq\", attrs[0].oid)\n    assert_equal(\"msExtReq\", attrs[1].oid)\n    assert_equal(exts, get_ext_req(attrs[0].value))\n    assert_equal(exts, get_ext_req(attrs[1].value))\n  end\n\n  def test_sign_digest_instance\n    req1 = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    req2 = issue_csr(0, @dn, @rsa1, OpenSSL::Digest.new(\"SHA256\"))\n    assert_equal(req1.to_der, req2.to_der)\n  end\n\n  def test_sign_and_verify\n    req = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    assert_equal(true, req.verify(@rsa1))\n    assert_equal(false, req.verify(@rsa2))\n    ec = OpenSSL::PKey::EC.generate(\"prime256v1\")\n    assert_equal(false, request_error_returns_false { req.verify(ec) })\n    req.subject = OpenSSL::X509::Name.parse_rfc2253(\"CN=FooBarFooBar,C=JP\")\n    assert_equal(false, req.verify(@rsa1))\n  end\n\n  def test_sign_and_verify_nil_digest\n    # Ed25519 is not FIPS-approved.\n    omit_on_fips\n    ed25519 = OpenSSL::PKey::generate_key(\"ED25519\")\n    req = issue_csr(0, @dn, ed25519, nil)\n    assert_equal(false, request_error_returns_false { req.verify(@rsa1) })\n    assert_equal(false, request_error_returns_false { req.verify(@rsa2) })\n    assert_equal(false, req.verify(OpenSSL::PKey::generate_key(\"ED25519\")))\n    assert_equal(true, req.verify(ed25519))\n    req.public_key = @rsa1\n    assert_equal(false, req.verify(ed25519))\n  end\n\n  def test_dup\n    req = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    assert_equal(req.to_der, req.dup.to_der)\n  end\n\n  def test_eq\n    req1 = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    req2 = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    req3 = issue_csr(0, @dn, @rsa1, \"SHA512\")\n\n    assert_equal false, req1 == 12345\n    assert_equal true, req1 == req2\n    assert_equal false, req1 == req3\n  end\n\n  def test_marshal\n    req = issue_csr(0, @dn, @rsa1, \"SHA256\")\n    deserialized = Marshal.load(Marshal.dump(req))\n\n    assert_equal req.to_der, deserialized.to_der\n  end\n\n  private\n\n  def request_error_returns_false\n    yield\n  rescue OpenSSL::X509::RequestError\n    false\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/test_x509store.rb",
    "content": "# frozen_string_literal: true\nrequire_relative \"utils\"\n\nif defined?(OpenSSL)\n\nclass OpenSSL::TestX509Store < OpenSSL::TestCase\n  def test_store_new\n    # v2.3.0 emits explicit warning\n    assert_warning(/new does not take any arguments/) {\n      OpenSSL::X509::Store.new(123)\n    }\n  end\n\n  def test_add_file_path\n    ca_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign,keyCertSign\", true],\n    ]\n    cert1_subj = OpenSSL::X509::Name.parse_rfc2253(\"CN=Cert 1\")\n    cert1_key = Fixtures.pkey(\"rsa-1\")\n    cert1 = issue_cert(cert1_subj, cert1_key, 1, ca_exts, nil, nil)\n    cert2_subj = OpenSSL::X509::Name.parse_rfc2253(\"CN=Cert 2\")\n    cert2_key = Fixtures.pkey(\"rsa-2\")\n    cert2 = issue_cert(cert2_subj, cert2_key, 1, ca_exts, nil, nil)\n\n    # X509::Store#add_file reads concatenated PEM file\n    tmpfile = Tempfile.open { |f| f << cert1.to_pem << cert2.to_pem; f }\n    store = OpenSSL::X509::Store.new\n    assert_equal false, store.verify(cert1)\n    assert_equal false, store.verify(cert2)\n    store.add_file(tmpfile.path)\n    assert_equal true, store.verify(cert1)\n    assert_equal true, store.verify(cert2)\n\n    # X509::Store#add_path\n    Dir.mktmpdir do |dir|\n      hash1 = \"%08x.%d\" % [cert1_subj.hash, 0]\n      File.write(File.join(dir, hash1), cert1.to_pem)\n      store = OpenSSL::X509::Store.new\n      store.add_path(dir)\n\n      assert_equal true, store.verify(cert1)\n      assert_equal false, store.verify(cert2)\n    end\n\n    # OpenSSL < 1.1.1 leaks an error on a duplicate certificate\n    assert_nothing_raised { store.add_file(tmpfile.path) }\n    assert_equal [], OpenSSL.errors\n\n    # Non-String is given\n    assert_raise(TypeError) { store.add_file(nil) }\n  ensure\n    tmpfile and tmpfile.close!\n  end\n\n  def test_verify_simple\n    ca_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign,keyCertSign\", true],\n    ]\n    ca1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Root CA\")\n    ca1_key = Fixtures.pkey(\"rsa-1\")\n    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil)\n    ca2 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Intermediate CA\")\n    ca2_key = Fixtures.pkey(\"rsa-2\")\n    ca2_cert = issue_cert(ca2, ca2_key, 2, ca_exts, ca1_cert, ca1_key)\n\n    ee_exts = [\n      [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n    ]\n    ee1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=EE 1\")\n    ee1_key = Fixtures.pkey(\"rsa-3\")\n    ee1_cert = issue_cert(ee1, ee1_key, 10, ee_exts, ca2_cert, ca2_key)\n\n    # Nothing trusted\n    store = OpenSSL::X509::Store.new\n    assert_equal(false, store.verify(ee1_cert, [ca2_cert, ca1_cert]))\n    assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, store.error)\n    assert_match(/self.signed/i, store.error_string)\n\n    # CA1 trusted, CA2 missing\n    store = OpenSSL::X509::Store.new\n    store.add_cert(ca1_cert)\n    assert_equal(false, store.verify(ee1_cert))\n    assert_equal(OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, store.error)\n\n    # CA1 trusted, CA2 supplied\n    store = OpenSSL::X509::Store.new\n    store.add_cert(ca1_cert)\n    assert_equal(true, store.verify(ee1_cert, [ca2_cert]))\n    assert_match(/ok/i, store.error_string)\n    assert_equal(OpenSSL::X509::V_OK, store.error)\n    assert_equal([ee1_cert, ca2_cert, ca1_cert], store.chain)\n\n    # Manually instantiated StoreContext\n    # Nothing trusted\n    store = OpenSSL::X509::Store.new\n    ctx = OpenSSL::X509::StoreContext.new(store, ee1_cert)\n    assert_nil(ctx.current_cert)\n    assert_nil(ctx.current_crl)\n    assert_equal(false, ctx.verify)\n    assert_equal(OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, ctx.error)\n    assert_equal(0, ctx.error_depth)\n    assert_equal([ee1_cert], ctx.chain)\n    assert_equal(ee1_cert, ctx.current_cert)\n  end\n\n  def test_verify_callback\n    ca_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign,keyCertSign\", true],\n    ]\n    ca1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Root CA\")\n    ca1_key = Fixtures.pkey(\"rsa-1\")\n    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil)\n    ca2 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Intermediate CA\")\n    ca2_key = Fixtures.pkey(\"rsa-2\")\n    ca2_cert = issue_cert(ca2, ca2_key, 2, ca_exts, ca1_cert, ca1_key)\n\n    ee_exts = [\n      [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n    ]\n    ee1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=EE 1\")\n    ee1_key = Fixtures.pkey(\"rsa-3\")\n    ee1_cert = issue_cert(ee1, ee1_key, 10, ee_exts, ca2_cert, ca2_key)\n\n    # verify_callback on X509::Store is called with proper arguments\n    cb_calls = []\n    store = OpenSSL::X509::Store.new\n    store.verify_callback = -> (preverify_ok, sctx) {\n      cb_calls << [preverify_ok, sctx.current_cert]\n      preverify_ok\n    }\n    store.add_cert(ca1_cert)\n    assert_equal(true, store.verify(ee1_cert, [ca2_cert]))\n    assert_include([2, 3, 4, 5], cb_calls.size)\n    cb_calls.each do |pre_ok, cert|\n      assert_equal(true, pre_ok)\n      assert_include([ca1_cert, ca2_cert, ee1_cert], cert)\n    end\n\n    # verify_callback can change verification result\n    store = OpenSSL::X509::Store.new\n    store.verify_callback = -> (preverify_ok, sctx) {\n      next preverify_ok if sctx.current_cert != ee1_cert\n      sctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION\n      false\n    }\n    store.add_cert(ca1_cert)\n    assert_equal(false, store.verify(ee1_cert, [ca2_cert]))\n    assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, store.error)\n\n    # Exception raised by verify_callback is currently suppressed, and is\n    # treated as a non-truthy return (with warning)\n    store = OpenSSL::X509::Store.new\n    store.verify_callback = -> (preverify_ok, sctx) {\n      raise \"suppressed\"\n    }\n    store.add_cert(ca1_cert)\n    assert_warning(/exception in verify_callback/) {\n      assert_equal(false, store.verify(ee1_cert, [ca2_cert]))\n    }\n\n    # The block given to X509::Store#verify replaces it\n    called = nil\n    store = OpenSSL::X509::Store.new\n    store.verify_callback = -> (preverify_ok, sctx) { called = :store; preverify_ok }\n    store.add_cert(ca1_cert)\n    blk = proc { |preverify_ok, sctx| called = :block; preverify_ok }\n    assert_equal(true, store.verify(ee1_cert, [ca2_cert], &blk))\n    assert_equal(:block, called)\n  end\n\n  def test_verify_purpose\n    ca_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign,keyCertSign\", true],\n    ]\n    ca1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Root CA\")\n    ca1_key = Fixtures.pkey(\"rsa-1\")\n    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil)\n\n    ee_exts = [\n      [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n    ]\n    ee1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=EE 1\")\n    ee1_key = Fixtures.pkey(\"rsa-3\")\n    ee1_cert = issue_cert(ee1, ee1_key, 10, ee_exts, ca1_cert, ca1_key)\n\n    # Purpose not set\n    store = OpenSSL::X509::Store.new\n    store.add_cert(ca1_cert)\n    assert_equal(true, store.verify(ca1_cert))\n    assert_equal(true, store.verify(ee1_cert))\n\n    # Purpose set to X509::PURPOSE_SSL_CLIENT; keyUsage is checked\n    store = OpenSSL::X509::Store.new\n    store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN\n    store.add_cert(ca1_cert)\n    assert_equal(true, store.verify(ca1_cert))\n    assert_equal(false, store.verify(ee1_cert))\n  end\n\n  def test_verify_validity_period\n    # Creating test certificates with validity periods:\n    #\n    #  now-5000                 now-1000    now+1000                  now+5000\n    # CA1:|---------------------------------------------------------------|\n    # EE1:|---------------------------------------------------------------|\n    # EE2:|-------------------------|\n    # EE3:                                      |-------------------------|\n    now = Time.now\n    ca_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign,keyCertSign\", true],\n    ]\n    ca1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Root CA\")\n    ca1_key = Fixtures.pkey(\"rsa-1\")\n    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil,\n                          not_before: now - 5000, not_after: now + 5000)\n\n    ee_exts = [\n      [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n    ]\n    ee1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=EE 1\")\n    ee1_key = Fixtures.pkey(\"rsa-1\")\n    ee1_cert = issue_cert(ee1, ee1_key, 11, ee_exts, ca1_cert, ca1_key,\n                          not_before: now - 5000, not_after: now + 5000)\n    ee2 = OpenSSL::X509::Name.parse_rfc2253(\"CN=EE 2\")\n    ee2_key = Fixtures.pkey(\"rsa-2\")\n    ee2_cert = issue_cert(ee2, ee2_key, 12, ee_exts, ca1_cert, ca1_key,\n                          not_before: now - 5000, not_after: now - 1000)\n    ee3 = OpenSSL::X509::Name.parse_rfc2253(\"CN=EE 3\")\n    ee3_key = Fixtures.pkey(\"rsa-3\")\n    ee3_cert = issue_cert(ee3, ee3_key, 13, ee_exts, ca1_cert, ca1_key,\n                          not_before: now + 1000, not_after: now + 5000)\n\n    # Using system time\n    store = OpenSSL::X509::Store.new\n    store.add_cert(ca1_cert)\n    assert_equal(true, store.verify(ee1_cert))\n    assert_equal(false, store.verify(ee2_cert))\n    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)\n    assert_equal(false, store.verify(ee3_cert))\n    assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error)\n\n    # Time set to now-2000; EE2 is still valid\n    store = OpenSSL::X509::Store.new\n    store.time = now - 2000\n    store.add_cert(ca1_cert)\n    assert_equal(true, store.verify(ee1_cert))\n    assert_equal(true, store.verify(ee2_cert))\n    assert_equal(false, store.verify(ee3_cert))\n    assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error)\n  end\n\n  def test_verify_with_crl\n    ca_exts = [\n      [\"basicConstraints\", \"CA:TRUE\", true],\n      [\"keyUsage\", \"cRLSign,keyCertSign\", true],\n    ]\n    ca1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Root CA\")\n    ca1_key = Fixtures.pkey(\"rsa-1\")\n    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil)\n    ca2 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Intermediate CA\")\n    ca2_key = Fixtures.pkey(\"rsa-2\")\n    ca2_cert = issue_cert(ca2, ca2_key, 2, ca_exts, ca1_cert, ca1_key)\n\n    ee_exts = [\n      [\"keyUsage\", \"keyEncipherment,digitalSignature\", true],\n    ]\n    ee1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=EE 1\")\n    ee1_key = Fixtures.pkey(\"rsa-3\")\n    ee1_cert = issue_cert(ee1, ee1_key, 10, ee_exts, ca2_cert, ca2_key)\n    ee2 = OpenSSL::X509::Name.parse_rfc2253(\"CN=EE 2\")\n    ee2_key = Fixtures.pkey(\"rsa-3\")\n    ee2_cert = issue_cert(ee2, ee2_key, 20, ee_exts, ca2_cert, ca2_key)\n\n    # OpenSSL uses time(2) while Time.now uses clock_gettime(CLOCK_REALTIME),\n    # and there may be difference, so giving 50 seconds margin.\n    now = Time.now - 50\n    revoke_info = []\n    ca1_crl1 = issue_crl(revoke_info, 1, now, now+1800, [], ca1_cert, ca1_key, \"sha256\")\n    revoke_info = [ [2, now, 1], ]\n    ca1_crl2 = issue_crl(revoke_info, 2, now, now+1800, [], ca1_cert, ca1_key, \"sha256\")\n\n    revoke_info = [ [20, now, 1], ]\n    ca2_crl1 = issue_crl(revoke_info, 1, now, now+1800, [], ca2_cert, ca2_key, \"sha256\")\n    revoke_info = []\n    ca2_crl2 = issue_crl(revoke_info, 2, now-100, now-1, [], ca2_cert, ca2_key, \"sha256\")\n\n    # CRL check required, but no CRL supplied\n    store = OpenSSL::X509::Store.new\n    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK\n    store.add_cert(ca1_cert)\n    assert_equal(false, store.verify(ca2_cert))\n    assert_equal(OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL, store.error)\n\n    # Intermediate CA revoked EE2\n    store = OpenSSL::X509::Store.new\n    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK\n    store.add_cert(ca1_cert)\n    store.add_crl(ca1_crl1) # revoke no cert\n    store.add_crl(ca2_crl1) # revoke ee2_cert\n    assert_equal(true, store.verify(ca2_cert))\n    assert_equal(true, store.verify(ee1_cert, [ca2_cert]))\n    assert_equal(false, store.verify(ee2_cert, [ca2_cert]))\n\n    # Root CA revoked Intermediate CA; Intermediate CA revoked EE2\n    store = OpenSSL::X509::Store.new\n    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK\n    store.add_cert(ca1_cert)\n    store.add_crl(ca1_crl2) # revoke ca2_cert\n    store.add_crl(ca2_crl1) # revoke ee2_cert\n    assert_equal(false, store.verify(ca2_cert))\n    # Validity of intermediate CAs is not checked by default\n    assert_equal(true, store.verify(ee1_cert, [ca2_cert]))\n    assert_equal(false, store.verify(ee2_cert, [ca2_cert]))\n\n    # Same as above, but with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL\n    store = OpenSSL::X509::Store.new\n    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL\n    store.add_cert(ca1_cert)\n    store.add_crl(ca1_crl2) # revoke ca2_cert\n    store.add_crl(ca2_crl1) # revoke ee2_cert\n    assert_equal(false, store.verify(ca2_cert))\n    assert_equal(false, store.verify(ee1_cert, [ca2_cert]))\n    assert_equal(false, store.verify(ee2_cert, [ca2_cert]))\n\n    # Expired CRL supplied\n    store = OpenSSL::X509::Store.new\n    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL\n    store.add_cert(ca1_cert)\n    store.add_cert(ca2_cert)\n    store.add_crl(ca1_crl1)\n    store.add_crl(ca2_crl2) # issued by ca2 but expired\n    assert_equal(true, store.verify(ca2_cert))\n    assert_equal(false, store.verify(ee1_cert))\n    assert_equal(OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED, store.error)\n    assert_equal(false, store.verify(ee2_cert))\n  end\n\n  def test_add_cert_duplicate\n    ca1 = OpenSSL::X509::Name.parse_rfc2253(\"CN=Root CA\")\n    ca1_key = Fixtures.pkey(\"rsa-1\")\n    ca1_cert = issue_cert(ca1, ca1_key, 1, [], nil, nil)\n    store = OpenSSL::X509::Store.new\n    store.add_cert(ca1_cert)\n    assert_nothing_raised {\n      store.add_cert(ca1_cert)  # add same certificate twice\n    }\n\n    now = Time.now\n    revoke_info = []\n    crl1 = issue_crl(revoke_info, 1, now, now+1800, [],\n                     ca1_cert, ca1_key, \"sha256\")\n    revoke_info = [ [2, now, 1], ]\n    crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [],\n                     ca1_cert, ca1_key, \"sha256\")\n    store.add_crl(crl1)\n    assert_nothing_raised {\n      store.add_crl(crl2) # add CRL issued by same CA twice.\n    }\n  end\n\n  def test_dup\n    store = OpenSSL::X509::Store.new\n    assert_raise(NoMethodError) { store.dup }\n    ctx = OpenSSL::X509::StoreContext.new(store)\n    assert_raise(NoMethodError) { ctx.dup }\n  end\n\n  def test_ctx_cleanup\n    # Deprecated in Ruby 1.9.3\n    cert  = OpenSSL::X509::Certificate.new\n    store = OpenSSL::X509::Store.new\n    ctx   = OpenSSL::X509::StoreContext.new(store, cert, [])\n    assert_warning(/cleanup/) { ctx.cleanup }\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/ut_eof.rb",
    "content": "# frozen_string_literal: true\nrequire 'test/unit'\n\nif defined?(OpenSSL)\n\nmodule OpenSSL::TestEOF\n  def test_getbyte_eof\n    open_file(\"\") {|f| assert_nil f.getbyte }\n  end\n\n  def test_readbyte_eof\n    open_file(\"\") {|f| assert_raise(EOFError) { f.readbyte } }\n  end\n\n  def test_eof_0\n    open_file(\"\") {|f|\n      assert_equal(\"\", f.read(0))\n      assert_equal(\"\", f.read(0))\n      assert_equal(\"\", f.read)\n      assert_equal(\"\", f.read(0))\n      assert_equal(\"\", f.read(0))\n    }\n    open_file(\"\") {|f|\n      assert_nil(f.read(1))\n      assert_equal(\"\", f.read)\n      assert_nil(f.read(1))\n    }\n    open_file(\"\") {|f|\n      s = +\"x\"\n      assert_equal(\"\", f.read(nil, s))\n      assert_equal(\"\", s)\n    }\n    open_file(\"\") {|f|\n      s = +\"x\"\n      assert_nil(f.read(10, s))\n      assert_equal(\"\", s)\n    }\n  end\n\n  def test_eof_0_rw\n    return unless respond_to? :open_file_rw\n    open_file_rw(\"\") {|f|\n      assert_equal(\"\", f.read)\n      assert_equal(\"\", f.read)\n      assert_equal(0, f.syswrite(\"\"))\n      assert_equal(\"\", f.read)\n    }\n  end\n\n  def test_eof_1\n    open_file(\"a\") {|f|\n      assert_equal(\"\", f.read(0))\n      assert_equal(\"a\", f.read(1))\n      assert_equal(\"\" , f.read(0))\n      assert_equal(\"\" , f.read(0))\n      assert_equal(\"\", f.read)\n      assert_equal(\"\", f.read(0))\n      assert_equal(\"\", f.read(0))\n    }\n    open_file(\"a\") {|f|\n      assert_equal(\"a\", f.read(1))\n      assert_nil(f.read(1))\n    }\n    open_file(\"a\") {|f|\n      assert_equal(\"a\", f.read(2))\n      assert_nil(f.read(1))\n      assert_equal(\"\", f.read)\n      assert_nil(f.read(1))\n    }\n    open_file(\"a\") {|f|\n      assert_equal(\"a\", f.read)\n      assert_nil(f.read(1))\n      assert_equal(\"\", f.read)\n      assert_nil(f.read(1))\n    }\n    open_file(\"a\") {|f|\n      assert_equal(\"a\", f.read(2))\n      assert_equal(\"\", f.read)\n      assert_equal(\"\", f.read)\n    }\n    open_file(\"a\") {|f|\n      assert_equal(\"a\", f.read)\n      assert_equal(\"\", f.read(0))\n    }\n    open_file(\"a\") {|f|\n      s = +\"x\"\n      assert_equal(\"a\", f.read(nil, s))\n      assert_equal(\"a\", s)\n    }\n    open_file(\"a\") {|f|\n      s = +\"x\"\n      assert_equal(\"a\", f.read(10, s))\n      assert_equal(\"a\", s)\n    }\n  end\n\n  def test_eof_2\n    open_file(\"\") {|f|\n      assert_equal(\"\", f.read)\n      assert_predicate(f, :eof?)\n    }\n  end\n\n  def test_eof_3\n    open_file(\"\") {|f|\n      assert_predicate(f, :eof?)\n    }\n  end\n\n  module Seek\n    def open_file_seek(content, pos)\n      open_file(content) do |f|\n        f.seek(pos)\n        yield f\n      end\n    end\n\n    def test_eof_0_seek\n      open_file_seek(\"\", 10) {|f|\n        assert_equal(10, f.pos)\n        assert_equal(\"\", f.read(0))\n        assert_equal(\"\", f.read)\n        assert_equal(\"\", f.read(0))\n        assert_equal(\"\", f.read)\n      }\n    end\n\n    def test_eof_1_seek\n      open_file_seek(\"a\", 10) {|f|\n        assert_equal(\"\", f.read)\n        assert_equal(\"\", f.read)\n      }\n      open_file_seek(\"a\", 1) {|f|\n        assert_equal(\"\", f.read)\n        assert_equal(\"\", f.read)\n      }\n    end\n  end\nend\n\nend\n"
  },
  {
    "path": "test/openssl/utils.rb",
    "content": "# frozen_string_literal: true\nbegin\n  require \"openssl\"\nrescue LoadError\nend\n\nrequire \"test/unit\"\nrequire \"core_assertions\"\nrequire \"tempfile\"\nrequire \"socket\"\n\nif defined?(OpenSSL)\n\nmodule OpenSSL::TestUtils\n  module Fixtures\n    module_function\n\n    def pkey(name)\n      OpenSSL::PKey.read(read_file(\"pkey\", name))\n    end\n\n    def read_file(category, name)\n      @file_cache ||= {}\n      @file_cache[[category, name]] ||=\n        File.read(File.join(__dir__, \"fixtures\", category, name + \".pem\"))\n    end\n  end\n\n  module_function\n\n  def generate_cert(dn, key, serial, issuer,\n                    not_before: nil, not_after: nil)\n    cert = OpenSSL::X509::Certificate.new\n    issuer = cert unless issuer\n    cert.version = 2\n    cert.serial = serial\n    cert.subject = dn\n    cert.issuer = issuer.subject\n    cert.public_key = key\n    now = Time.now\n    cert.not_before = not_before || now - 3600\n    cert.not_after = not_after || now + 3600\n    cert\n  end\n\n\n  def issue_cert(dn, key, serial, extensions, issuer, issuer_key,\n                 not_before: nil, not_after: nil, digest: \"sha256\")\n    cert = generate_cert(dn, key, serial, issuer,\n                         not_before: not_before, not_after: not_after)\n    issuer = cert unless issuer\n    issuer_key = key unless issuer_key\n    ef = OpenSSL::X509::ExtensionFactory.new\n    ef.subject_certificate = cert\n    ef.issuer_certificate = issuer\n    extensions.each{|oid, value, critical|\n      cert.add_extension(ef.create_extension(oid, value, critical))\n    }\n    cert.sign(issuer_key, digest)\n    cert\n  end\n\n  def issue_crl(revoke_info, serial, lastup, nextup, extensions,\n                issuer, issuer_key, digest)\n    crl = OpenSSL::X509::CRL.new\n    crl.issuer = issuer.subject\n    crl.version = 1\n    crl.last_update = lastup\n    crl.next_update = nextup\n    revoke_info.each{|rserial, time, reason_code|\n      revoked = OpenSSL::X509::Revoked.new\n      revoked.serial = rserial\n      revoked.time = time\n      enum = OpenSSL::ASN1::Enumerated(reason_code)\n      ext = OpenSSL::X509::Extension.new(\"CRLReason\", enum)\n      revoked.add_extension(ext)\n      crl.add_revoked(revoked)\n    }\n    ef = OpenSSL::X509::ExtensionFactory.new\n    ef.issuer_certificate = issuer\n    ef.crl = crl\n    crlnum = OpenSSL::ASN1::Integer(serial)\n    crl.add_extension(OpenSSL::X509::Extension.new(\"crlNumber\", crlnum))\n    extensions.each{|oid, value, critical|\n      crl.add_extension(ef.create_extension(oid, value, critical))\n    }\n    crl.sign(issuer_key, digest)\n    crl\n  end\n\n  def get_subject_key_id(cert, hex: true)\n    asn1_cert = OpenSSL::ASN1.decode(cert)\n    tbscert   = asn1_cert.value[0]\n    pkinfo    = tbscert.value[6]\n    publickey = pkinfo.value[1]\n    pkvalue   = publickey.value\n    digest = OpenSSL::Digest.digest('SHA1', pkvalue)\n    if hex\n      digest.unpack(\"H2\"*20).join(\":\").upcase\n    else\n      digest\n    end\n  end\n\n  def openssl?(major = nil, minor = nil, fix = nil, patch = 0, status = 0)\n    return false if OpenSSL::OPENSSL_VERSION.include?(\"LibreSSL\") || OpenSSL::OPENSSL_VERSION.include?(\"AWS-LC\")\n    return true unless major\n    OpenSSL::OPENSSL_VERSION_NUMBER >=\n      major * 0x10000000 + minor * 0x100000 + fix * 0x1000 + patch * 0x10 +\n      status * 0x1\n  end\n\n  def libressl?(major = nil, minor = nil, fix = nil)\n    version = OpenSSL::OPENSSL_VERSION.scan(/LibreSSL (\\d+)\\.(\\d+)\\.(\\d+).*/)[0]\n    return false unless version\n    !major || (version.map(&:to_i) <=> [major, minor, fix]) >= 0\n  end\n\n  def aws_lc?\n    OpenSSL::OPENSSL_VERSION.include?(\"AWS-LC\")\n  end\nend\n\nclass OpenSSL::TestCase < Test::Unit::TestCase\n  include OpenSSL::TestUtils\n  extend OpenSSL::TestUtils\n  include Test::Unit::CoreAssertions\n\n  def setup\n    if ENV[\"OSSL_GC_STRESS\"] == \"1\"\n      GC.stress = true\n    end\n  end\n\n  def teardown\n    if ENV[\"OSSL_GC_STRESS\"] == \"1\"\n      GC.stress = false\n    end\n    # OpenSSL error stack must be empty\n    assert_equal([], OpenSSL.errors)\n  end\n\n  # Omit the tests in FIPS.\n  #\n  # For example, the password based encryption used in the PEM format uses MD5\n  # for deriving the encryption key from the password, and MD5 is not\n  # FIPS-approved.\n  #\n  # See https://github.com/openssl/openssl/discussions/21830#discussioncomment-6865636\n  # for details.\n  def omit_on_fips\n    return unless OpenSSL.fips_mode\n\n    omit <<~MESSAGE\n      Only for OpenSSL non-FIPS with the following possible reasons:\n      * A testing logic is non-FIPS specific.\n      * An encryption used in the test is not FIPS-approved.\n    MESSAGE\n  end\n\n  def omit_on_non_fips\n    return if OpenSSL.fips_mode\n\n    omit \"Only for OpenSSL FIPS\"\n  end\nend\n\nclass OpenSSL::SSLTestCase < OpenSSL::TestCase\n  RUBY = EnvUtil.rubybin\n  ITERATIONS = ($0 == __FILE__) ? 100 : 10\n\n  def setup\n    super\n    @ca_key  = Fixtures.pkey(\"rsa-1\")\n    @svr_key = Fixtures.pkey(\"rsa-2\")\n    @cli_key = Fixtures.pkey(\"rsa-3\")\n    @ca  = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=CA\")\n    @svr = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=localhost\")\n    @cli = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=localhost\")\n    @ca_exts = [\n      [\"basicConstraints\",\"CA:TRUE\",true],\n      [\"keyUsage\",\"cRLSign,keyCertSign\",true],\n    ]\n    @ee_exts = [\n      [\"keyUsage\",\"keyEncipherment,digitalSignature\",true],\n    ]\n    @ca_cert  = issue_cert(@ca, @ca_key, 1, @ca_exts, nil, nil)\n    @svr_cert = issue_cert(@svr, @svr_key, 2, @ee_exts, @ca_cert, @ca_key)\n    @cli_cert = issue_cert(@cli, @cli_key, 3, @ee_exts, @ca_cert, @ca_key)\n    @server = nil\n  end\n\n  def readwrite_loop(ctx, ssl)\n    while line = ssl.gets\n      ssl.write(line)\n    end\n  end\n\n  def start_server(verify_mode: OpenSSL::SSL::VERIFY_NONE,\n                   ctx_proc: nil, server_proc: method(:readwrite_loop),\n                   accept_proc: proc{},\n                   ignore_listener_error: false, &block)\n    IO.pipe {|stop_pipe_r, stop_pipe_w|\n      ctx = OpenSSL::SSL::SSLContext.new\n      ctx.cert = @svr_cert\n      ctx.key = @svr_key\n      ctx.verify_mode = verify_mode\n      ctx_proc.call(ctx) if ctx_proc\n\n      Socket.do_not_reverse_lookup = true\n      tcps = TCPServer.new(\"127.0.0.1\", 0)\n      port = tcps.connect_address.ip_port\n\n      ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)\n\n      threads = []\n      begin\n        server_thread = Thread.new do\n          Thread.current.report_on_exception = false\n\n          begin\n            loop do\n              begin\n                readable, = IO.select([ssls, stop_pipe_r])\n                break if readable.include? stop_pipe_r\n                ssl = ssls.accept\n                accept_proc.call(ssl)\n              rescue OpenSSL::SSL::SSLError, IOError, Errno::EBADF, Errno::EINVAL,\n                     Errno::ECONNABORTED, Errno::ENOTSOCK, Errno::ECONNRESET\n                retry if ignore_listener_error\n                raise\n              end\n\n              th = Thread.new do\n                Thread.current.report_on_exception = false\n\n                begin\n                  server_proc.call(ctx, ssl)\n                ensure\n                  ssl.close\n                end\n                true\n              end\n              threads << th\n            end\n          ensure\n            tcps.close\n          end\n        end\n\n        client_thread = Thread.new do\n          Thread.current.report_on_exception = false\n\n          begin\n            block.call(port)\n          ensure\n            # Stop accepting new connection\n            stop_pipe_w.close\n            server_thread.join\n          end\n        end\n        threads.unshift client_thread\n      ensure\n        # Terminate existing connections. If a thread did 'pend', re-raise it.\n        pend = nil\n        threads.each { |th|\n          begin\n            timeout = EnvUtil.apply_timeout_scale(30)\n            th.join(timeout) or\n              th.raise(RuntimeError, \"[start_server] thread did not exit in #{timeout} secs\")\n          rescue Test::Unit::PendedError\n            pend = $!\n          rescue Exception\n          end\n        }\n        raise pend if pend\n        assert_join_threads(threads)\n      end\n    }\n  end\nend\n\nclass OpenSSL::PKeyTestCase < OpenSSL::TestCase\n  def check_component(base, test, keys)\n    keys.each { |comp|\n      assert_equal base.send(comp), test.send(comp)\n    }\n  end\n\n  def assert_sign_verify_false_or_error\n    ret = yield\n  rescue => e\n    assert_kind_of(OpenSSL::PKey::PKeyError, e)\n  else\n    assert_equal(false, ret)\n  end\n\n  def der_to_pem(der, pem_header)\n    # RFC 7468\n    <<~EOS\n    -----BEGIN #{pem_header}-----\n    #{[der].pack(\"m0\").scan(/.{1,64}/).join(\"\\n\")}\n    -----END #{pem_header}-----\n    EOS\n  end\n\n  def der_to_encrypted_pem(der, pem_header, password)\n    # OpenSSL encryption, non-standard\n    iv = 16.times.to_a.pack(\"C*\")\n    encrypted = OpenSSL::Cipher.new(\"aes-128-cbc\").encrypt.then { |cipher|\n      cipher.key = OpenSSL::Digest.digest(\"MD5\", password + iv[0, 8])\n      cipher.iv = iv\n      cipher.update(der) << cipher.final\n    }\n    <<~EOS\n    -----BEGIN #{pem_header}-----\n    Proc-Type: 4,ENCRYPTED\n    DEK-Info: AES-128-CBC,#{iv.unpack1(\"H*\").upcase}\n\n    #{[encrypted].pack(\"m0\").scan(/.{1,64}/).join(\"\\n\")}\n    -----END #{pem_header}-----\n    EOS\n  end\nend\n\nmodule OpenSSL::Certs\n  include OpenSSL::TestUtils\n\n  module_function\n\n  def ca_cert\n    ca = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/CN=Timestamp Root CA\")\n\n    ca_exts = [\n      [\"basicConstraints\",\"CA:TRUE,pathlen:1\",true],\n      [\"keyUsage\",\"keyCertSign, cRLSign\",true],\n      [\"subjectKeyIdentifier\",\"hash\",false],\n      [\"authorityKeyIdentifier\",\"keyid:always\",false],\n    ]\n    OpenSSL::TestUtils.issue_cert(ca, Fixtures.pkey(\"rsa2048\"), 1, ca_exts, nil, nil)\n  end\n\n  def ts_cert_direct(key, ca_cert)\n    dn = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/OU=Timestamp/CN=Server Direct\")\n\n    exts = [\n      [\"basicConstraints\",\"CA:FALSE\",true],\n      [\"keyUsage\",\"digitalSignature, nonRepudiation\", true],\n      [\"subjectKeyIdentifier\", \"hash\",false],\n      [\"authorityKeyIdentifier\",\"keyid,issuer\", false],\n      [\"extendedKeyUsage\", \"timeStamping\", true]\n    ]\n\n    OpenSSL::TestUtils.issue_cert(dn, key, 2, exts, ca_cert, Fixtures.pkey(\"rsa2048\"))\n  end\n\n  def intermediate_cert(key, ca_cert)\n    dn = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/OU=Timestamp/CN=Timestamp Intermediate CA\")\n\n    exts = [\n      [\"basicConstraints\",\"CA:TRUE,pathlen:0\",true],\n      [\"keyUsage\",\"keyCertSign, cRLSign\",true],\n      [\"subjectKeyIdentifier\",\"hash\",false],\n      [\"authorityKeyIdentifier\",\"keyid:always\",false],\n    ]\n\n    OpenSSL::TestUtils.issue_cert(dn, key, 3, exts, ca_cert, Fixtures.pkey(\"rsa2048\"))\n  end\n\n  def ts_cert_ee(key, intermediate, im_key)\n    dn = OpenSSL::X509::Name.parse(\"/DC=org/DC=ruby-lang/OU=Timestamp/CN=Server End Entity\")\n\n    exts = [\n      [\"keyUsage\",\"digitalSignature, nonRepudiation\", true],\n      [\"subjectKeyIdentifier\", \"hash\",false],\n      [\"authorityKeyIdentifier\",\"keyid,issuer\", false],\n      [\"extendedKeyUsage\", \"timeStamping\", true]\n    ]\n\n    OpenSSL::TestUtils.issue_cert(dn, key, 4, exts, intermediate, im_key)\n  end\nend\n\nend\n"
  },
  {
    "path": "tool/openssl_fips.cnf.tmpl",
    "content": "config_diagnostics = 1\nopenssl_conf = openssl_init\n\n# It seems that the .include needs an absolute path.\n.include OPENSSL_DIR/ssl/fipsmodule.cnf\n\n[openssl_init]\nproviders = provider_sect\nalg_section = algorithm_sect\n\n[provider_sect]\nfips = fips_sect\nbase = base_sect\n\n[base_sect]\nactivate = 1\n\n[algorithm_sect]\ndefault_properties = fips=yes\n"
  }
]