openssl icon indicating copy to clipboard operation
openssl copied to clipboard

pkeys are immutable on OpenSSL 3.0\e[0m (OpenSSL::PKey::PKeyError)

Open ykpoh opened this issue 2 years ago • 2 comments

HI, how do I use the existing private key and public key to encrypt the message? The keys are immutable now.

Fastfile:821:in `private_key=': \e[31m[!] pkeys are immutable on OpenSSL 3.0\e[0m (OpenSSL::PKey::PKeyError)

Environment:

ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [arm64-darwin21]
openssl (3.1.0, default: 2.2.0)
fastlane | 2.212.2 | ✅ Up-To-Date

Sample Code:

def get_force_update_message
    message = "message"
    private_key = "sample_private_key"
    public_key = "sample_public_key"

    # encrypt
    group = OpenSSL::PKey::EC::Group.new('secp256k1')
    key = OpenSSL::PKey::EC.new(group)
    key.private_key = OpenSSL::BN.new(private_key, 16)

    signature = key.dsa_sign_asn1(message)
    signature_base64 = Base64.encode64(signature).gsub("\n", "")

    # verify
    public_key_bn = OpenSSL::BN.new(public_key, 16)
    key.public_key = OpenSSL::PKey::EC::Point.new(group, public_key_bn)
    key.dsa_verify_asn1(message, signature)

    return "#{message}&#{signature_base64}"
  end

Error:

[17:13:51]: Error in your Fastfile at line 821
[17:13:51]:     819:	    group = OpenSSL::PKey::EC::Group.new('secp256k1')
[17:13:51]:     820:	    key = OpenSSL::PKey::EC.new(group)
[17:13:51]:  => 821:	    key.private_key = OpenSSL::BN.new(private_key, 16)
[17:13:51]:     822:	
[17:13:51]:     823:	    signature = key.dsa_sign_asn1(message)
[17:13:51]: pkeys are immutable on OpenSSL 3.0

+------+----------------------+-------------+
|             fastlane summary              |
+------+----------------------+-------------+
| Step | Action               | Time (in s) |
+------+----------------------+-------------+
| 1    | default_platform     | 0           |
| 2    | xcodes               | 0           |
| 3    | ensure_env_vars      | 0           |
| 4    | set_info_plist_value | 0           |
| 5    | ensure_env_vars      | 0           |
+------+----------------------+-------------+

[17:13:51]: fastlane finished with errors

Looking for related GitHub issues on fastlane/fastlane...

Found no similar issues. To create a new issue, please visit:
https://github.com/fastlane/fastlane/issues/new
Run `fastlane env` to append the fastlane environment to your issue
Fastfile:821:in `private_key=': \e[31m[!] pkeys are immutable on OpenSSL 3.0\e[0m (OpenSSL::PKey::PKeyError)
	from Fastfile:821:in `get_force_update_message'
	from Fastfile:252:in `block (2 levels) in parsing_binding'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/lane.rb:33:in `call'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/runner.rb:49:in `block in execute'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/runner.rb:45:in `chdir'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/runner.rb:45:in `execute'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/lane_manager.rb:47:in `cruise_lane'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/command_line_handler.rb:36:in `handle'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/commands_generator.rb:110:in `block (2 levels) in run'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/commander-4.6.0/lib/commander/command.rb:187:in `call'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/commander-4.6.0/lib/commander/command.rb:157:in `run'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/commander-4.6.0/lib/commander/runner.rb:444:in `run_active_command'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb:124:in `run!'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/commander-4.6.0/lib/commander/delegates.rb:18:in `run!'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/commands_generator.rb:354:in `run'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/commands_generator.rb:43:in `start'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/fastlane/lib/fastlane/cli_tools_distributor.rb:123:in `take_off'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/gems/fastlane-2.212.2/bin/fastlane:23:in `<top (required)>'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/bin/fastlane:25:in `load'
	from /opt/homebrew/Cellar/fastlane/2.212.2/libexec/bin/fastlane:25:in `<main>'

ykpoh avatar May 11 '23 09:05 ykpoh

Looks like it's being worked on @ https://github.com/ruby/openssl/pull/555 .

As for now, workarounds can be found here:

  • https://github.com/ruby/openssl/issues/498
  • https://github.com/ruby/openssl/pull/555#issuecomment-1440079803

sylph01 avatar Jul 14 '23 01:07 sylph01

In case anyone else is looking, DER formatting for public key and private key is slightly different. Here is the code I use to take raw hex public and private keys and load them into an OpenSSL::PKey::EC object:

    @curve = 'prime256v1'
    def pkey_from_private_key(private_key)
      public_key = restore_public_key private_key

      group = OpenSSL::PKey::EC::Group.new(@curve)

      private_key_bn   = OpenSSL::BN.new(private_key, 16)
      public_key_bn    = OpenSSL::BN.new(public_key, 16)
      public_key_point = OpenSSL::PKey::EC::Point.new(group, public_key_bn)

      asn1 = OpenSSL::ASN1::Sequence(
        [
          OpenSSL::ASN1::Integer.new(1),
          OpenSSL::ASN1::OctetString(private_key_bn.to_s(2)),
          OpenSSL::ASN1::ObjectId(@curve, 0, :EXPLICIT),
          OpenSSL::ASN1::BitString(public_key_point.to_octet_string(:uncompressed), 1, :EXPLICIT)
        ]
      )

      OpenSSL::PKey::EC.new(asn1.to_der)
    end

    def restore_public_key(private_key)
      private_bn = OpenSSL::BN.new private_key, 16
      group = OpenSSL::PKey::EC::Group.new @curve
      public_bn = group.generator.mul(private_bn).to_bn
      public_bn = OpenSSL::PKey::EC::Point.new(group, public_bn).to_bn

      public_bn.to_s(16).downcase
    end

    def pkey_from_public_key(public_key)
      group = OpenSSL::PKey::EC::Group.new(@curve)

      public_key_bn    = OpenSSL::BN.new(public_key, 16)
      public_key_point = OpenSSL::PKey::EC::Point.new(group, public_key_bn)

      asn1 = OpenSSL::ASN1::Sequence.new(
        [
          OpenSSL::ASN1::Sequence.new([
                                        OpenSSL::ASN1::ObjectId.new('id-ecPublicKey'),
                                        OpenSSL::ASN1::ObjectId.new(group.curve_name)
                                      ]),
          OpenSSL::ASN1::BitString.new(public_key_point.to_octet_string(:uncompressed))
        ]
      )

      OpenSSL::PKey::EC.new(asn1.to_der)
    end

    pkey_private_key = pkey_from_private_key('eeef3fba531e545464e63a45612f15de207eb676c464e5736c76ff5e500384cf')
    pkey_public_key = pkey_from_public_key('046c2f610637495461e3a03e76f17860e6a24be250c9992a5406b3c905411b35a70fa907540c35061035be589f97b394fc2c290c2a1a4ccacedfd3d935a9584594')

Hope others find this useful.

jonmchan avatar Oct 22 '23 04:10 jonmchan