Project

General

Profile

Actions

Feature #12354

closed

PKey::EC Can't output public key pem when private key exists

Added by armour (Armour Comms) over 6 years ago. Updated 13 days ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:75387]

Description

Steps to reproduce:

Create EC key:

key = OpenSSL::PKey::EC.new("prime256v1")
key.generate_key

Try and output in pem format

key.to_pem #Outputs private key pem
key.public_key.to_pem #Error

In order to output a public key pem, a new key object must be created with no private key:

key_pub = OpenSSL::PKey::EC.new(key.group)
key_pub.public_key = key.public_key

Output pem

key_pub.to_pem #Success!

From viewing the source, http://rxr.whitequark.org/mri/source/ext/openssl/ossl_pkey_ec.c#466 it seems that if the key is private there is no way to output a public key for that key object

Updated by hsbt (Hiroshi SHIBATA) over 6 years ago

  • Description updated (diff)
  • Status changed from Open to Assigned
  • Assignee set to rhenium (Kazuki Yamaguchi)

Updated by jeremyevans0 (Jeremy Evans) about 3 years ago

  • ruby -v deleted (ruby 2.2.4p230 (2015-12-16 revision 53155) [x86_64-linux])
  • Backport deleted (2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN)
  • Tracker changed from Bug to Feature

The following is a way to generate a PEM for a OpenSSL::PKey::EC with both a private and a public key without allocating a new OpenSSL::PKey::EC:

pk = key.private_key
key.private_key = nil
key.to_pem
key.private_key = key

I agree that this approach is suboptimal, and it may be worthwhile to add a method for this, or a keyword argument to to_pem. However, that is a request for a new feature, not a bug fix.

I checked and OpenSSL::PKey::RSA doesn't have the same issue because OpenSSL::PKey::RSA#public_key returns OpenSSL::PKey::RSA (OpenSSL::PKey::EC returns OpenSSL::PKey::EC::Point). However, it still requires allocating a new OpenSSL::PKey::RSA object.

Updated by brandur (Brandur Leach) 15 days ago

If you're linked against OpenSSL >= 3, the workarounds suggested here don't seem to work any longer because a pkey is not allowed to be modified:

Failure/Error: pub.public_key = SIGNING_KEY.public_key

OpenSSL::PKey::PKeyError:
  pkeys are immutable on OpenSSL 3.0
# ./app/pellet.rb:41:in `public_key='

And seen from Ruby's OpenSSL source:

static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
{
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
    rb_raise(ePKeyError, "pkeys are immutable on OpenSSL 3.0");
#else
...

I looked around for some other workaround, but I wasn't able to find one (although I don't know this code well, so I'm hoping someone else can suggest one). For what it's worth, I'd intuitively expect something like key.public_key.to_pem to work.

Given the OpenSSL 3 incompatibility, I wonder if this should be upgraded back to a bug?

Updated by rhenium (Kazuki Yamaguchi) 13 days ago

  • Status changed from Assigned to Closed

openssl v2.2 added OpenSSL::PKey::PKey#public_to_pem and #public_to_der for this purpose.

https://github.com/ruby/openssl/pull/297

Ruby 3.0 includes v2.2 by default.

Actions

Also available in: Atom PDF