{"record":{"id":"1937b1a0f381f52f","repo":"ruby/ruby","slug":"openssl-pkey-dh-is-immutable-on-openssl-3-0-use","errorCode":null,"errorMessage":"OpenSSL::PKey::DH is immutable on OpenSSL 3.0; use OpenSSL::PKey.generate_key instead","messagePattern":"OpenSSL::PKey::DH is immutable on OpenSSL 3\\.0; use OpenSSL::PKey\\.generate_key instead","errorType":"exception","errorClass":"OpenSSL::PKey::PKeyError","httpStatus":null,"severity":"error","filePath":"ext/openssl/lib/openssl/pkey.rb","lineNumber":108,"sourceCode":"    # 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","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/ruby/ruby/blob/0e5b888e1c355f3f728f2659f085820937dada48/ext/openssl/lib/openssl/pkey.rb#L90-L126","documentation":"OpenSSL 3.0 made key objects immutable, so the in-place OpenSSL::PKey::DH#generate_key! (which wrote pub_key/priv_key into the same object) can no longer be implemented. Ruby/OpenSSL raises PKeyError whenever generate_key! is called while linked against OpenSSL 3.0 or newer, pointing at OpenSSL::PKey.generate_key, the functional-style replacement. The version check runs before any key material is inspected, so even a fully parameterized DH object raises.","triggerScenarios":"Any call to dh.generate_key! on OpenSSL::PKey::DH when OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000, regardless of whether the receiver has p/g parameters set.","commonSituations":"Upgrading the OS or Ruby build from OpenSSL 1.1.1 to 3.x (Ubuntu 22.04, Debian 12, RHEL 9); legacy scripts that copy DH parameters via public_key and then generate a key in place; older versions of gems such as net-ssh calling generate_key! internally.","solutions":["Replace dh.generate_key! with dh = OpenSSL::PKey.generate_key(dh_params), using the returned new key.","If you first copied parameters (dh.public_key or a params-only PEM), feed that parameter object straight into OpenSSL::PKey.generate_key.","Upgrade gems that call generate_key! internally (older net-ssh and similar).","Running against OpenSSL 1.1.1 avoids the raise but is unsupported; treat it only as a temporary stopgap."],"exampleFix":"# before (OpenSSL 1.1.1 era)\ndh = OpenSSL::PKey::DH.new(2048)\ndh.generate_key! # raises PKeyError on OpenSSL 3.0\n\n# after\ndh_params = OpenSSL::PKey::DH.new(2048)\ndh = OpenSSL::PKey.generate_key(dh_params)","handlingStrategy":"fallback","validationCode":"dh = if OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000\n  OpenSSL::PKey.generate_key(dh_params) # OpenSSL 3.0+\nelse\n  dh_params.generate_key!             # OpenSSL 1.1.x\nend","typeGuard":null,"tryCatchPattern":"begin\n  dh.generate_key!\nrescue OpenSSL::PKey::PKeyError\n  dh = OpenSSL::PKey.generate_key(dh)\nend","preventionTips":["Treat PKey objects as immutable under OpenSSL 3.0 and derive new keys functionally.","Grep the codebase and Gemfile for generate_key! and public_key when upgrading OpenSSL.","Assert the expected OpenSSL::OPENSSL_VERSION_NUMBER in CI."],"tags":["openssl","ruby","pkey","dh","openssl-3","migration"],"backgroundTag":"openssl-3-0-migration","analyzedSha":"0e5b888e1c355f3f728f2659f085820937dada48","analyzedAt":"2026-08-21T14:25:43.473Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}