OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Stephen Farrell

Hiya,

My question: how does one setup an EVP_PKEY for a NIST
curve (e.g. p256) key pair when one has the private key
in an octet string using the latest OpenSSL 3.0.0 high
level APIs?

I'm trying to get rid of deprecation warnings from my
code for HPKE [1] when dealing with NIST curves using
the new (I guess?) OSSL_PARAM_* approach. I'm failing
at the moment;-)

So, given an octet string from a set of test vectors
(e.g. [2]) what's the proper way to setup an EVP_PKEY
for that to allow one to validate the test vectors?

Happy to try produce a stand-alone example for this
in the next few days if one doesn't exist (I've not
found one so far).

Thanks,
Stephen.

[1]
https://github.com/sftcd/happykey/blob/7d52d34c516ab58ca1433004ff82b2a6a82eea4c/hpke.c#L1263
[2] https://github.com/cfrg/draft-irtf-cfrg-hpke

OpenPGP_0x5AB2FAF17B172BEA.asc (10K) Download Attachment
OpenPGP_signature (855 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

OpenSSL - User mailing list
Hi Stephen :)

The API you'll want to use is EVP_PKEY_fromdata(); there's
a stubbed out example of using it to make an EVP_PKEY with
EC group parameters at
https://github.com/openssl/openssl/issues/14258#issuecomment-783351031
but the translation to also specify OSSL_PKEY_PARAM_PRIV_KEY
(and possibly OSSL_PKEY_PARAM_PUB_KEY; I forget if you need
to pass both) should be fairly straightforward.

Let us know if you run into trouble with that route.

-Ben

On Mon, Mar 08, 2021 at 02:23:36AM +0000, Stephen Farrell wrote:

>
> Hiya,
>
> My question: how does one setup an EVP_PKEY for a NIST
> curve (e.g. p256) key pair when one has the private key
> in an octet string using the latest OpenSSL 3.0.0 high
> level APIs?
>
> I'm trying to get rid of deprecation warnings from my
> code for HPKE [1] when dealing with NIST curves using
> the new (I guess?) OSSL_PARAM_* approach. I'm failing
> at the moment;-)
>
> So, given an octet string from a set of test vectors
> (e.g. [2]) what's the proper way to setup an EVP_PKEY
> for that to allow one to validate the test vectors?
>
> Happy to try produce a stand-alone example for this
> in the next few days if one doesn't exist (I've not
> found one so far).
>
> Thanks,
> Stephen.
>
> [1] https://github.com/sftcd/happykey/blob/7d52d34c516ab58ca1433004ff82b2a6a82eea4c/hpke.c#L1263
> [2] https://github.com/cfrg/draft-irtf-cfrg-hpke

pub   RSA 4096/7B172BEA 2017-12-22 Stephen Farrell (2017) <[hidden email]>
> sub   RSA 4096/36CB8BB6 2017-12-22
>



Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Stephen Farrell

Hiya,

On 08/03/2021 02:37, Benjamin Kaduk wrote:
> Hi Stephen :)
>
> The API you'll want to use is EVP_PKEY_fromdata(); there's
> a stubbed out example of using it to make an EVP_PKEY with
> EC group parameters at
> https://github.com/openssl/openssl/issues/14258#issuecomment-783351031
> but the translation to also specify OSSL_PKEY_PARAM_PRIV_KEY
> (and possibly OSSL_PKEY_PARAM_PUB_KEY; I forget if you need
> to pass both) should be fairly straightforward.

Thanks for that! I worked around a few things and still need
to tidy-up but got things working that way without any more
deprecation warnings.

>
> Let us know if you run into trouble with that route.

One outstanding issue is that I still need different code
paths for NIST curves vs. 25519 & 448 - is that just me
(quite likely:-) or should these new APIs hide differences
between those different curves?

Thanks again,
S.


>
> -Ben
>
> On Mon, Mar 08, 2021 at 02:23:36AM +0000, Stephen Farrell wrote:
>>
>> Hiya,
>>
>> My question: how does one setup an EVP_PKEY for a NIST
>> curve (e.g. p256) key pair when one has the private key
>> in an octet string using the latest OpenSSL 3.0.0 high
>> level APIs?
>>
>> I'm trying to get rid of deprecation warnings from my
>> code for HPKE [1] when dealing with NIST curves using
>> the new (I guess?) OSSL_PARAM_* approach. I'm failing
>> at the moment;-)
>>
>> So, given an octet string from a set of test vectors
>> (e.g. [2]) what's the proper way to setup an EVP_PKEY
>> for that to allow one to validate the test vectors?
>>
>> Happy to try produce a stand-alone example for this
>> in the next few days if one doesn't exist (I've not
>> found one so far).
>>
>> Thanks,
>> Stephen.
>>
>> [1] https://github.com/sftcd/happykey/blob/7d52d34c516ab58ca1433004ff82b2a6a82eea4c/hpke.c#L1263
>> [2] https://github.com/cfrg/draft-irtf-cfrg-hpke
>
> pub   RSA 4096/7B172BEA 2017-12-22 Stephen Farrell (2017) <[hidden email]>
>> sub   RSA 4096/36CB8BB6 2017-12-22
>>
>
>
>

OpenPGP_0x5AB2FAF17B172BEA.asc (10K) Download Attachment
OpenPGP_signature (855 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

OpenSSL - User mailing list
On Tue, Mar 09, 2021 at 02:44:20AM +0000, Stephen Farrell wrote:

>
> Hiya,
>
> On 08/03/2021 02:37, Benjamin Kaduk wrote:
> > Hi Stephen :)
> >
> > The API you'll want to use is EVP_PKEY_fromdata(); there's
> > a stubbed out example of using it to make an EVP_PKEY with
> > EC group parameters at
> > https://github.com/openssl/openssl/issues/14258#issuecomment-783351031
> > but the translation to also specify OSSL_PKEY_PARAM_PRIV_KEY
> > (and possibly OSSL_PKEY_PARAM_PUB_KEY; I forget if you need
> > to pass both) should be fairly straightforward.
>
> Thanks for that! I worked around a few things and still need
> to tidy-up but got things working that way without any more
> deprecation warnings.
>
> >
> > Let us know if you run into trouble with that route.
>
> One outstanding issue is that I still need different code
> paths for NIST curves vs. 25519 & 448 - is that just me
> (quite likely:-) or should these new APIs hide differences
> between those different curves?

I would have expected that the API should hide the differences
other than the group name ... but these APIs are still pretty
new to me, too.  If you can point me at your code I might have
more to say.


-Ben
Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Stephen Farrell

Hiya,

On 09/03/2021 03:09, Benjamin Kaduk wrote:
> I would have expected that the API should hide the differences
> other than the group name ... but these APIs are still pretty
> new to me, too.  If you can point me at your code I might have
> more to say.

Will check it out some more, tidy the code up and get back
later/tomorrow,

Cheers,
S.

OpenPGP_0x5AB2FAF17B172BEA.asc (10K) Download Attachment
OpenPGP_signature (855 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Stephen Farrell
In reply to this post by OpenSSL - User mailing list

Hiya,

On 09/03/2021 03:09, Benjamin Kaduk wrote:
> I would have expected that the API should hide the differences
> other than the group name ... but these APIs are still pretty
> new to me, too.  If you can point me at your code I might have
> more to say.

So again it's probably my fault but I'm still not seeing the
same behaviour for NIST and non-NIST curves. I made up what
I hope is a fairly simple bit of test code [1] so that might
help clarify where I'm wrong or (less likely) where a change
in the library might be useful.

As I build the test code, the p256 cases seem to work, with
or without the public key, but both 25519 cases fail. In my
(still untidy:-) HPKE code EVP_PKEY_new_raw_private_key
for the non-NIST curves works, but not for NIST curves. So I
have an ok workaround, even if the fault's not mine, which
it of course probably is:-)

Cheers,
S.

[1] https://github.com/sftcd/happykey/blob/master/test2evp.c

OpenPGP_0x5AB2FAF17B172BEA.asc (10K) Download Attachment
OpenPGP_signature (855 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Tomas Mraz-3
On Wed, 2021-03-10 at 00:53 +0000, Stephen Farrell wrote:

> Hiya,
>
> On 09/03/2021 03:09, Benjamin Kaduk wrote:
> > I would have expected that the API should hide the differences
> > other than the group name ... but these APIs are still pretty
> > new to me, too.  If you can point me at your code I might have
> > more to say.
>
> So again it's probably my fault but I'm still not seeing the
> same behaviour for NIST and non-NIST curves. I made up what
> I hope is a fairly simple bit of test code [1] so that might
> help clarify where I'm wrong or (less likely) where a change
> in the library might be useful.
>
> As I build the test code, the p256 cases seem to work, with
> or without the public key, but both 25519 cases fail. In my
> (still untidy:-) HPKE code EVP_PKEY_new_raw_private_key
> for the non-NIST curves works, but not for NIST curves. So I
> have an ok workaround, even if the fault's not mine, which
> it of course probably is:-)

Not sure if there are any other issues, but the public key parameter
should be "encoded-pub-key" AFAIK.

Tomas Mraz


Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Matt Caswell-2
In reply to this post by Stephen Farrell


On 10/03/2021 00:53, Stephen Farrell wrote:

>
> Hiya,
>
> On 09/03/2021 03:09, Benjamin Kaduk wrote:
>> I would have expected that the API should hide the differences
>> other than the group name ... but these APIs are still pretty
>> new to me, too.  If you can point me at your code I might have
>> more to say.
>
> So again it's probably my fault but I'm still not seeing the
> same behaviour for NIST and non-NIST curves. I made up what
> I hope is a fairly simple bit of test code [1] so that might
> help clarify where I'm wrong or (less likely) where a change
> in the library might be useful.
>
> As I build the test code, the p256 cases seem to work, with
> or without the public key, but both 25519 cases fail. In my
> (still untidy:-) HPKE code EVP_PKEY_new_raw_private_key
> for the non-NIST curves works, but not for NIST curves. So I
> have an ok workaround, even if the fault's not mine, which
> it of course probably is:-)

Hi Stephen

There are two important things to understand that your code was not
quite handling correctly:

1) X25519/X448/ED25519/ED448 are treated as different key types to
"traditional" EC. They really are very different things: different OIDs,
different standards, different file formats, different key formats etc.
So while the "traditional" EC curves have the key type "EC", we have
separate key types of "X25519", "X448", "ED25519" and "ED448"

2) The type of the parameters is dependent on the key type. So a private
key in "EC" is an integer. But a private key for "X25519" is an octet
string.

Refer to:

https://www.openssl.org/docs/manmaster/man7/EVP_PKEY-EC.html
https://www.openssl.org/docs/manmaster/man7/EVP_PKEY-X25519.html


I made these changes to your test code to get it to work:

$ diff -u test2evp.c test2evp2.c
--- test2evp.c 2021-03-10 08:47:59.467451154 +0000
+++ test2evp2.c 2021-03-10 09:03:47.258657721 +0000
@@ -29,6 +29,7 @@
  #include <openssl/core_names.h>

  int bufs2evp(
+        const char *keytype,
          char *groupname,
          unsigned char *privbuf, size_t privbuflen,
          unsigned char *pubuf, size_t pubuflen,
@@ -41,38 +42,38 @@
      OSSL_PARAM_BLD *param_bld=NULL;;
      OSSL_PARAM *params = NULL;

-    priv = BN_bin2bn(privbuf, privbuflen, NULL);
-    if (!priv) {
-        erv=__LINE__; goto err;
-    }
      param_bld = OSSL_PARAM_BLD_new();
      if (!param_bld) {
          erv=__LINE__; goto err;
      }
      if (pubuf && pubuflen>0) {
-        if (OSSL_PARAM_BLD_push_utf8_string(param_bld, "group",
groupname,0)!=1) {
-            erv=__LINE__; goto err;
-        }
-        if (OSSL_PARAM_BLD_push_BN(param_bld, "priv", priv)!=1) {
-            erv=__LINE__; goto err;
-        }
          if (OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", pubuf,
pubuflen)!=1) {
              erv=__LINE__; goto err;
          }
          params = OSSL_PARAM_BLD_to_param(param_bld);
-    } else {
-        if (OSSL_PARAM_BLD_push_utf8_string(param_bld, "group",
groupname,0)!=1) {
+    }
+    if (groupname != NULL && OSSL_PARAM_BLD_push_utf8_string(param_bld,
"group", groupname,0)!=1) {
+        erv=__LINE__; goto err;
+    }
+    if (strcmp(keytype, "EC") == 0) {
+        priv = BN_bin2bn(privbuf, privbuflen, NULL);
+        if (!priv) {
              erv=__LINE__; goto err;
-        }
+        }
          if (OSSL_PARAM_BLD_push_BN(param_bld, "priv", priv)!=1) {
              erv=__LINE__; goto err;
          }
-        params = OSSL_PARAM_BLD_to_param(param_bld);
+    } else {
+        if (OSSL_PARAM_BLD_push_octet_string(param_bld, "priv",
privbuf, privbuflen)!=1) {
+            erv=__LINE__; goto err;
+        }
      }
+    params = OSSL_PARAM_BLD_to_param(param_bld);
+
      if (!params) {
          erv=__LINE__; goto err;
      }
-    ctx = EVP_PKEY_CTX_new_from_name(NULL,"EC", NULL);
+    ctx = EVP_PKEY_CTX_new_from_name(NULL,keytype, NULL);
      if (ctx == NULL) {
          erv=__LINE__; goto err;
      }
@@ -167,7 +168,7 @@
       * First do a p-256 one that works, then an x25519 one that does not.
       */

-    rv=bufs2evp("P-256",nprivbuf,nprivlen,npubbuf,npublen,&retkey);
+    rv=bufs2evp("EC","P-256",nprivbuf,nprivlen,npubbuf,npublen,&retkey);
      if (rv==1) {
          printf("P-256 with key pair worked\n");
      } else {
@@ -175,7 +176,7 @@
      }
      EVP_PKEY_free(retkey);retkey=NULL;

-    rv=bufs2evp("P-256",nprivbuf,nprivlen,NULL,0,&retkey);
+    rv=bufs2evp("EC","P-256",nprivbuf,nprivlen,NULL,0,&retkey);
      if (rv==1) {
          printf("P-256 with just private key worked\n");
      } else {
@@ -183,7 +184,7 @@
      }
      EVP_PKEY_free(retkey);retkey=NULL;

-    rv=bufs2evp("X25519",xprivbuf,xprivlen,xpubbuf,xpublen,&retkey);
+    rv=bufs2evp("X25519",NULL,xprivbuf,xprivlen,xpubbuf,xpublen,&retkey);
      if (rv==1) {
          printf("X25519 with key pair worked\n");
      } else {
@@ -191,7 +192,7 @@
      }
      EVP_PKEY_free(retkey);retkey=NULL;

-    rv=bufs2evp("X25519",xprivbuf,xprivlen,NULL,0,&retkey);
+    rv=bufs2evp("X25519",NULL,xprivbuf,xprivlen,NULL,0,&retkey);
      if (rv==1) {
          printf("X25519 with just private key worked\n");
      } else {


Matt
Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Stephen Farrell

Thanks Matt,

On 10/03/2021 09:12, Matt Caswell wrote:

>
>
> On 10/03/2021 00:53, Stephen Farrell wrote:
>>
>> Hiya,
>>
>> On 09/03/2021 03:09, Benjamin Kaduk wrote:
>>> I would have expected that the API should hide the differences
>>> other than the group name ... but these APIs are still pretty
>>> new to me, too.  If you can point me at your code I might have
>>> more to say.
>>
>> So again it's probably my fault but I'm still not seeing the
>> same behaviour for NIST and non-NIST curves. I made up what
>> I hope is a fairly simple bit of test code [1] so that might
>> help clarify where I'm wrong or (less likely) where a change
>> in the library might be useful.
>>
>> As I build the test code, the p256 cases seem to work, with
>> or without the public key, but both 25519 cases fail. In my
>> (still untidy:-) HPKE code EVP_PKEY_new_raw_private_key
>> for the non-NIST curves works, but not for NIST curves. So I
>> have an ok workaround, even if the fault's not mine, which
>> it of course probably is:-)
>
> Hi Stephen
>
> There are two important things to understand that your code was not
> quite handling correctly:
>
> 1) X25519/X448/ED25519/ED448 are treated as different key types to
> "traditional" EC. They really are very different things: different OIDs,
> different standards, different file formats, different key formats etc.
> So while the "traditional" EC curves have the key type "EC", we have
> separate key types of "X25519", "X448", "ED25519" and "ED448"
>
> 2) The type of the parameters is dependent on the key type. So a private
> key in "EC" is an integer. But a private key for "X25519" is an octet
> string.
I had tried all those, but not in the right combination,
so thanks! My test code works now with your changes. (It's
still at [1] and feel free to use as an example if that's
useful.)

It seems a pity that one has to special case in two ways
there (both keytype and groupname) but I can live with it,

Thanks again,
S.

[1] https://github.com/sftcd/happykey/blob/master/test2evp.c

>
> Refer to:
>
> https://www.openssl.org/docs/manmaster/man7/EVP_PKEY-EC.html
> https://www.openssl.org/docs/manmaster/man7/EVP_PKEY-X25519.html
>
>
> I made these changes to your test code to get it to work:
>
> $ diff -u test2evp.c test2evp2.c
> --- test2evp.c    2021-03-10 08:47:59.467451154 +0000
> +++ test2evp2.c    2021-03-10 09:03:47.258657721 +0000
> @@ -29,6 +29,7 @@
>   #include <openssl/core_names.h>
>
>   int bufs2evp(
> +        const char *keytype,
>           char *groupname,
>           unsigned char *privbuf, size_t privbuflen,
>           unsigned char *pubuf, size_t pubuflen,
> @@ -41,38 +42,38 @@
>       OSSL_PARAM_BLD *param_bld=NULL;;
>       OSSL_PARAM *params = NULL;
>
> -    priv = BN_bin2bn(privbuf, privbuflen, NULL);
> -    if (!priv) {
> -        erv=__LINE__; goto err;
> -    }
>       param_bld = OSSL_PARAM_BLD_new();
>       if (!param_bld) {
>           erv=__LINE__; goto err;
>       }
>       if (pubuf && pubuflen>0) {
> -        if (OSSL_PARAM_BLD_push_utf8_string(param_bld, "group",
> groupname,0)!=1) {
> -            erv=__LINE__; goto err;
> -        }
> -        if (OSSL_PARAM_BLD_push_BN(param_bld, "priv", priv)!=1) {
> -            erv=__LINE__; goto err;
> -        }
>           if (OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", pubuf,
> pubuflen)!=1) {
>               erv=__LINE__; goto err;
>           }
>           params = OSSL_PARAM_BLD_to_param(param_bld);
> -    } else {
> -        if (OSSL_PARAM_BLD_push_utf8_string(param_bld, "group",
> groupname,0)!=1) {
> +    }
> +    if (groupname != NULL && OSSL_PARAM_BLD_push_utf8_string(param_bld,
> "group", groupname,0)!=1) {
> +        erv=__LINE__; goto err;
> +    }
> +    if (strcmp(keytype, "EC") == 0) {
> +        priv = BN_bin2bn(privbuf, privbuflen, NULL);
> +        if (!priv) {
>               erv=__LINE__; goto err;
> -        }
> +        }
>           if (OSSL_PARAM_BLD_push_BN(param_bld, "priv", priv)!=1) {
>               erv=__LINE__; goto err;
>           }
> -        params = OSSL_PARAM_BLD_to_param(param_bld);
> +    } else {
> +        if (OSSL_PARAM_BLD_push_octet_string(param_bld, "priv",
> privbuf, privbuflen)!=1) {
> +            erv=__LINE__; goto err;
> +        }
>       }
> +    params = OSSL_PARAM_BLD_to_param(param_bld);
> +
>       if (!params) {
>           erv=__LINE__; goto err;
>       }
> -    ctx = EVP_PKEY_CTX_new_from_name(NULL,"EC", NULL);
> +    ctx = EVP_PKEY_CTX_new_from_name(NULL,keytype, NULL);
>       if (ctx == NULL) {
>           erv=__LINE__; goto err;
>       }
> @@ -167,7 +168,7 @@
>        * First do a p-256 one that works, then an x25519 one that does not.
>        */
>
> -    rv=bufs2evp("P-256",nprivbuf,nprivlen,npubbuf,npublen,&retkey);
> +    rv=bufs2evp("EC","P-256",nprivbuf,nprivlen,npubbuf,npublen,&retkey);
>       if (rv==1) {
>           printf("P-256 with key pair worked\n");
>       } else {
> @@ -175,7 +176,7 @@
>       }
>       EVP_PKEY_free(retkey);retkey=NULL;
>
> -    rv=bufs2evp("P-256",nprivbuf,nprivlen,NULL,0,&retkey);
> +    rv=bufs2evp("EC","P-256",nprivbuf,nprivlen,NULL,0,&retkey);
>       if (rv==1) {
>           printf("P-256 with just private key worked\n");
>       } else {
> @@ -183,7 +184,7 @@
>       }
>       EVP_PKEY_free(retkey);retkey=NULL;
>
> -    rv=bufs2evp("X25519",xprivbuf,xprivlen,xpubbuf,xpublen,&retkey);
> +    rv=bufs2evp("X25519",NULL,xprivbuf,xprivlen,xpubbuf,xpublen,&retkey);
>       if (rv==1) {
>           printf("X25519 with key pair worked\n");
>       } else {
> @@ -191,7 +192,7 @@
>       }
>       EVP_PKEY_free(retkey);retkey=NULL;
>
> -    rv=bufs2evp("X25519",xprivbuf,xprivlen,NULL,0,&retkey);
> +    rv=bufs2evp("X25519",NULL,xprivbuf,xprivlen,NULL,0,&retkey);
>       if (rv==1) {
>           printf("X25519 with just private key worked\n");
>       } else {
>
>
> Matt

OpenPGP_0x5AB2FAF17B172BEA.asc (10K) Download Attachment
OpenPGP_signature (855 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: OpenSSL 3.0.0 APIs for creating an EVP_PKEY from a p256 private key octet string

Matt Caswell-2


On 10/03/2021 12:08, Stephen Farrell wrote:
> It seems a pity that one has to special case in two ways
> there (both keytype and groupname) but I can live with it,

For X25519 you can actually pass a groupname of "x25519" through if you
want to keep everything consistent. But it's not strictly necessary
since that is the only group supported by that keytype.

Matt