Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: [openssl-users] Naive: how to generate EC public key from EC private key?

643 views
Skip to first unread message

Viktor Dukhovni

unread,
Mar 17, 2016, 5:57:47 PM3/17/16
to

> On Mar 17, 2016, at 5:17 PM, Blumenthal, Uri - 0553 - MITLL <u...@ll.mit.edu> wrote:
>
> I’ve an extremely naïve question. I am generating ephemeral EC keys for ECDH, following the example in https://wiki.openssl.org/index.php/EVP_Key_and_Parameter_Generation
>
> But it looks like the example ends on generation of the private key:
> /* Generate the key */
> if (!EVP_PKEY_keygen(kctx, &key)) goto err;
>
>
> The next step must be obvious, but somehow I can’t figure it out. So my question is: from having EVP_PKEY *privateECKey how do I get EVP_PKEY *publicECKey?

The public key is always there. You either have both the public and private keys
or just the public key. So the same EVP_PKEY object holds both. What you do
next depends on what you want to do with the public key...

--
Viktor.

--
openssl-users mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users

Viktor Dukhovni

unread,
Mar 17, 2016, 7:01:18 PM3/17/16
to

> On Mar 17, 2016, at 6:32 PM, Blumenthal, Uri - 0553 - MITLL <u...@ll.mit.edu> wrote:
>
> Oh, and I'd much prefer to stay at the EVP level, rather than invoke BIO primitives for this task.

Well you can work with http://openssl.org/docs/manmaster/crypto/EC_KEY_key2buf.html
to extract EC public key octets. If you want an ASN.1 encoded "SPKI" object (i.e. an
X509_PUBKEY in OpenSSL) then you can use

X509_PUBKEY *pk = NULL;
unsigned char *buf = NULL;
EVP_PKEY *key;

key = ... ; /* Get a keypair */

if (X509_PUBKEY_set(&pk, key) <= 0) {
/* error */
}

len = i2d_X509_PUBKEY(pk, &buf);
if (len < 0 || buf == NULL) {
/* error */
}

/* buf contains ASN.1-encoded SPKI, use it */

OPENSSL_free(buf);
X509_PUBKEY_free(pk);
EVP_PKEY_free(key); /* If no longer needed */

A shorter version of the above is possible via i2d_PUBKEY() which
handles the creation, encoding and destruction of the intermediate
X509_PUBKEY:

int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp)
{
X509_PUBKEY *xpk = NULL;
int ret;
if (!a)
return 0;
if (!X509_PUBKEY_set(&xpk, a))
return 0;
ret = i2d_X509_PUBKEY(xpk, pp);
X509_PUBKEY_free(xpk);
return ret;
}


Looks like we need documentation for X509_PUBKEY_set() and friends...
Any volunteers?

X509_PUBKEY_free();
X509_PUBKEY_get();
X509_PUBKEY_get0();
X509_PUBKEY_get0_param();
X509_PUBKEY_new();
X509_PUBKEY_set();
X509_PUBKEY_set0_param();
d2i_DSA_PUBKEY_bio();
d2i_DSA_PUBKEY_fp();
d2i_EC_PUBKEY_bio();
d2i_EC_PUBKEY_fp();
d2i_PUBKEY_bio();
d2i_PUBKEY_fp();
d2i_RSA_PUBKEY_bio();
d2i_RSA_PUBKEY_fp();
i2d_DSA_PUBKEY_bio();
i2d_DSA_PUBKEY_fp();
i2d_EC_PUBKEY_bio();
i2d_EC_PUBKEY_fp();
i2d_PUBKEY_bio();
i2d_PUBKEY_fp();
i2d_RSA_PUBKEY_bio();
i2d_RSA_PUBKEY_fp();

Dr. Stephen Henson

unread,
Mar 17, 2016, 7:46:35 PM3/17/16
to
On Thu, Mar 17, 2016, Viktor Dukhovni wrote:

>
> > On Mar 17, 2016, at 6:32 PM, Blumenthal, Uri - 0553 - MITLL <u...@ll.mit.edu> wrote:
> >
> > Oh, and I'd much prefer to stay at the EVP level, rather than invoke BIO primitives for this task.
>
> Well you can work with http://openssl.org/docs/manmaster/crypto/EC_KEY_key2buf.html
> to extract EC public key octets.

That's only available in the master branch, only encodes the key value and not
its parameters and of course it only works for EC.
That's the preferred route as it uses the standard SubjectPublicKeyInfo
format and works with any supported public key type.

Steve.
--
Dr Stephen N. Henson. OpenSSL project core developer.
Commercial tech support now available see: http://www.openssl.org

Viktor Dukhovni

unread,
Mar 18, 2016, 4:18:22 PM3/18/16
to
On Fri, Mar 18, 2016 at 06:59:36PM +0000, Blumenthal, Uri - 0553 - MITLL wrote:

> Answered my own question: should use EVP_PKEY_bits(pkey) instead.

That's not the right way to determine the curve id.

> >How do I determine what curve the above key is on?

For that you need to determine the EVP_PKEY algorithm type:

int type = EVP_PKEY_base_id(pkey);

if (type == EVP_PKEY_EC) {
EC_KEY *key = EVP_PKEY_get0_EC_KEY(pkey);
EC_GROUP *group = EC_KEY_get0_group(key);

/* Use that group to generate more points */
}

So you don't need code to specifically identify the group, but if
you want to constrain the supported groups:

switch (EC_GROUP_get_curve_name(group)) {
case NID_undef:
default:
/* Unknown or not named group */

case NID_X9_62_prime256v1:
/* P-256 */
...

case NID_secp384r1:
/* P-384 */

...
}

--
Viktor.

Dr. Stephen Henson

unread,
Mar 18, 2016, 9:11:55 PM3/18/16
to
On Fri, Mar 18, 2016, Viktor Dukhovni wrote:

> On Fri, Mar 18, 2016 at 06:59:36PM +0000, Blumenthal, Uri - 0553 - MITLL wrote:
>
> > Answered my own question: should use EVP_PKEY_bits(pkey) instead.
>
> That's not the right way to determine the curve id.
>
> > >How do I determine what curve the above key is on?
>
> For that you need to determine the EVP_PKEY algorithm type:
>
> int type = EVP_PKEY_base_id(pkey);
>
> if (type == EVP_PKEY_EC) {
> EC_KEY *key = EVP_PKEY_get0_EC_KEY(pkey);
> EC_GROUP *group = EC_KEY_get0_group(key);
>
> /* Use that group to generate more points */
> }
>
> So you don't need code to specifically identify the group, but if
> you want to constrain the supported groups:
>
> switch (EC_GROUP_get_curve_name(group)) {
> case NID_undef:
> default:
> /* Unknown or not named group */
>
> case NID_X9_62_prime256v1:
> /* P-256 */
> ...
>
> case NID_secp384r1:
> /* P-384 */
>
> ...
> }
>

There is another way too. An EVP_PKEY can also be used to contain parameters
and it is permissible to pass a private or public key as a set of parameters.

In outline you call:

EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(privkey, NULL);
EVP_PKEY_keygen_init(pctx);
EVP_PKEY_keygen(pctx, &newkey);
EVP_PKEY_CTX_free(pctx);

This works with other algorithms like DSA/DH too so you'll probably want to
check the key is of the correct type first.

Steve.
--
Dr Stephen N. Henson. OpenSSL project core developer.
Commercial tech support now available see: http://www.openssl.org

Blumenthal, Uri - 0553 - MITLL

unread,
Mar 20, 2016, 10:33:21 PM3/20/16
to
Thank you!!

Now the code works (using the outline Stephen suggested, as it is simpler
:)!

I still have a few questions/issues.

1. EVP_PKEY_get0_EC_KEY(key) is only defined for 1.1. I had to use
EVP_PKEY_get1_EC_KEY(key) with 1.0.2g. (this is not a problem - just a
remark)

2. For some reason the following code does not work - subsequent requests
that involve pub key fail:

dup_ekey = EVP_PKEY_get1_EC_KEY(pubkey);
group = (EC_GROUP*) EC_KEY_get0_group(dup_ekey);
nid = EC_GROUP_get_curve_name(group);
printf("wrap: Deriving ECC keys over curve \"%s\"\n",
EC_curve_nid2nist(nid));
EC_GROUP_free(group);

EC_KEY_free(dup_ekey);

But if I move the two XXX_free() calls to the end of the function -
everything is fine. So in my working version of the code these lines are
just before the return, after everything has been done. But I don’t
understand why it behaves that way, given the man pages here:
https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_set1_RSA.html

3. If in the above fragment I try

dup_ekey = EVP_PKEY_assign_EC_KEY(pubkey);


Then the entire fragment does not work.

Thanks again for your help (as I said, with your guidance the code now
works), and I’d appreciate some light on the above peculiarities.
--
Regards,
Uri Blumenthal




On 3/18/16, 21:11, "openssl-users on behalf of Dr. Stephen Henson"

Jeffrey Walton

unread,
Mar 20, 2016, 10:38:16 PM3/20/16
to
> 2. For some reason the following code does not work - subsequent requests
> that involve pub key fail:
>
> dup_ekey = EVP_PKEY_get1_EC_KEY(pubkey);
> group = (EC_GROUP*) EC_KEY_get0_group(dup_ekey);
> nid = EC_GROUP_get_curve_name(group);
> printf("wrap: Deriving ECC keys over curve \"%s\"\n",
> EC_curve_nid2nist(nid));
> EC_GROUP_free(group);
>
> EC_KEY_free(dup_ekey);
>
> But if I move the two XXX_free() calls to the end of the function -
> everything is fine. So in my working version of the code these lines are
> just before the return, after everything has been done. But I don’t
> understand why it behaves that way, given the man pages here:
> https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_set1_RSA.html

get0 means the reference count was _not_ bumped, so the object should
not be free'd.

get1 means the reference count was incremented, and it needs an
accompanying free on the object.

I think the call to `EC_GROUP_free(group)` is superfluous and causing
memory corruption/double free.

Jeff

Viktor Dukhovni

unread,
Mar 20, 2016, 10:39:25 PM3/20/16
to

> On Mar 20, 2016, at 10:32 PM, Blumenthal, Uri - 0553 - MITLL <u...@ll.mit.edu> wrote:
>
> dup_ekey = EVP_PKEY_get1_EC_KEY(pubkey);
> group = (EC_GROUP*) EC_KEY_get0_group(dup_ekey);

Declare the group as:

const EC_GROUP *group;

Then:

group = EC_KEY_get0_group();

> nid = EC_GROUP_get_curve_name(group);
> printf("wrap: Deriving ECC keys over curve \"%s\"\n",
> EC_curve_nid2nist(nid));

This is fine.


> EC_GROUP_free(group);

This is very wrong. You're not supposed to free the group.
Note the "get0_group", you're not getting a copy...

--
Viktor.

Blumenthal, Uri - 0553 - MITLL

unread,
Mar 20, 2016, 11:02:06 PM3/20/16
to
Viktor and Jeffrey,

Thank you! Now I understand. And it works. ;)
--
Regards,
Uri Blumenthal




On 3/20/16, 22:38, "openssl-users on behalf of Viktor Dukhovni"
<openssl-us...@openssl.org on behalf of
0 new messages